diff options
Diffstat (limited to 'ipl/packs/idol')
47 files changed, 5790 insertions, 0 deletions
diff --git a/ipl/packs/idol/Makefile b/ipl/packs/idol/Makefile new file mode 100644 index 0000000..d39ac0e --- /dev/null +++ b/ipl/packs/idol/Makefile @@ -0,0 +1,23 @@ +# +# Sample makefile for compiling Idol +# +idol: idol.iol idolmain.u1 unix.u1 idolboot + ./idolboot idol unix.u1 idolmain.u1 + +idolboot: idolboot.icn unix.u1 + icont -s idolboot unix.u1 + +unix.u1: unix.icn + icont -s -c unix + +idolmain.u1: idolmain.icn + icont -s -c idolmain + + +# Build executable and copy to ../../iexe. +# (Nothing done in this case because the executable doesn't stand alone.) +Iexe: + + +Clean: + rm -rf *.u[12] idol idolboot idolmain unix idolcode.env diff --git a/ipl/packs/idol/NEW.8_0 b/ipl/packs/idol/NEW.8_0 new file mode 100644 index 0000000..102a109 --- /dev/null +++ b/ipl/packs/idol/NEW.8_0 @@ -0,0 +1,64 @@ +This document notes differences between Idol version 6 (the previous +distributed version) and the current release, version 8. See the +idol reference manual (idol.doc, TR 90-10) and the Idol man page +for a complete description of Idol. + +Summary of New Features (example/reference) + +* Constants (const bar := 3.1415, version := "Idol 8.0") +* Include files (#include foo.iol) +* Index meta-operator (x$["baz"]) +* Automatic installation (no "idol -install" step) +* Shared class environment (IDOLENV environment variable) +* Temporary environments (clean single-file translation) +* Contributed ports (Amiga, MPW, MS-DOS, MVS, OS/2, UNIX, VMS) + +Idol Version 8 incorporates significant improvements in usability without +any major changes in the object model used in the previous release. Code +from Idol release 6 may have to be recompiled but will function unchanged +under release 8. + +CONSTANTS + +Idol supports a "const" declaration for Icon values of type string, cset, +integer, and real. See the Idol reference manual for details. + +INCLUDE FILES + +Idol supports textual inclusion. This is intended primarily to facilitate +sharing of constant values amongst separately translated files. + +INDEX META OPERATOR + +x $[ y, z, ...] is shorthand notation for the expression x$index(y,z,...). +Many classes implement an index or lookup operation, and this notation +supports that operation as closely to Icon's syntax as possible. + +AUTOMATIC INSTALLATION + +The "idol -install" step required in the previous release is performed +automatically if required. + +SHARED CLASS ENVIRONMENT + +On systems supporting the getenv() function, the environment variable +IDOLENV may optionally denote a class code repository for use by all +Idol operations. This allows sharing of classes amongst programs +translated in different directories. + +TEMPORARY ENVIRONMENTS + +"Automatically installed environments" as described above are considered +temporary and automatically removed after successful compilation if +compilation consists of a single source file, and no IDOLENV variable +is present. + +CONTRIBUTED PORTS + +Icon enthusiasts transported Idol to several machines; these ports +were for version 6, but many or most of them will work for version 8. +They have been adapted to include new features to the best of my +abilities, but if you are not using MS-DOS you may want to examine +things and make adjustments. This should be much easier than writing +your own port, at any rate. I am available by e-mail or telephone +should questions arise. diff --git a/ipl/packs/idol/README b/ipl/packs/idol/README new file mode 100644 index 0000000..eab6f43 --- /dev/null +++ b/ipl/packs/idol/README @@ -0,0 +1,50 @@ +This is the Idol public distribution directory. +Read idol.man and idol.doc for details on running Idol. +Read systems.doc for system-dependent notes, such as how to +build Idol for your system. + +The Idol source is idol.iol; the Idol booting kit is idolboot.icn. +In addition to these two files, there is a system-specific Icon file +which must be linked in to produce an Idol executable: so far there +are files amiga.icn, mpw.icn, msdos.icn, mvs.icn, os2.icn, unix.icn, +and vms.icn. + +BUILDING IDOL + +If you are running MS-DOS, the file install.bat contains the sequence +of commands necessary to build Idol. This sequence consists of: + +(1) Compile idolboot with a line such as + icont -Sr1000 -SF30 -Si1000 idolboot msdos + +(2) Install an Idol environment directory with a line such as + iconx idolboot -install + +For MS-DOS, this generates a batch file named idolt.bat which +you would then execute to create the environment directory. +For other systems, idolboot creates the directory itself. + +(3) Translate Idol from its idol.iol source file with a line such as + iconx idolboot idol msdos.icn +(Again, on MS-DOS, this generates a batch file named idolt.bat +which you should then execute.) + +This makes a good initial test of the system's operation. + +In addition there are several other files with extension .iol; these +are unfinished fragments of Idol source code for your perusal. +Contributions are of course welcome! + +Note that Idol is still a work in progress, and this must be +considered a test distribution. Support for non-UNIX systems is +minimally tested; feel free to add code to support your system +and send it in. + +The -strict flag not only generates paranoid code for public field +access, it generates extra warning messages when inherited fields +are named in a subclass. + +The file idol.hqx is a Macintosh BinHex 4.0 file of configuration +material for Icon to run under MPW. + +Mail jeffery@ringer.cs.utas.edu when you have questions or bug fixes for Idol. diff --git a/ipl/packs/idol/amiga.icn b/ipl/packs/idol/amiga.icn new file mode 100644 index 0000000..b011937 --- /dev/null +++ b/ipl/packs/idol/amiga.icn @@ -0,0 +1,85 @@ +# +# @(#)amiga.icn 1.4 3/14/91 +# OS-specific code for Amiga Idol +# +global icontopt,cd,md,env,sysok,comp + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s[9:0] := "" + s ||:= \ext + return s +end + +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end + +procedure writesublink(s) + writelink(env||"/"||s) +end + +procedure envpath(filename) + return env||"/"||filename +end + +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + if "-t" == !args then comp := -2 + write("Installing idol environment in ",env) + if env ~== "" then mysystem(md||env) + fout := envopen("i_object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + mysystem("delete "||exe||".icn") + if \exec then { + write("Executing:") + exe := "iconx "||exe + every i := exec+1 to *args do exe ||:= " "||args[i] + return mysystem(exe) + } else return + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + if comp = -2 then return # -t --> don't call icont at all + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || ifile + every ifile := !idolfiles do rms ||:= " " || ifile || ".icn" + + mysystem("cd idolcode.env") + if icont(args) = \sysok + then every ifile := !idolfiles do mysystem("delete "||ifile||".icn") + mysystem("cd /") + return +end +procedure sysinitialize() + icontopt := " -Sr500 -SF30 -Si1000 " + cd := "cd " + md := "makedir " + env := getenv("IDOLENV") | "idolcode.env" + sysok := 0 +end diff --git a/ipl/packs/idol/autoparn.iol b/ipl/packs/idol/autoparn.iol new file mode 100644 index 0000000..64c85e2 --- /dev/null +++ b/ipl/packs/idol/autoparn.iol @@ -0,0 +1,15 @@ +# +# Here is a sample test of automatic parenthesizing +# +class autotest(public yo) + method foo(x) + return x + end +initially + self.yo := "yo, bro" +end + +procedure main() + x := autotest() + write(x$foo(x$yo)) # yo almost becomes a data item, notation-wise +end diff --git a/ipl/packs/idol/bi_test.iol b/ipl/packs/idol/bi_test.iol new file mode 100644 index 0000000..6e0b955 --- /dev/null +++ b/ipl/packs/idol/bi_test.iol @@ -0,0 +1,30 @@ +# +# Tests for the various builtins +# +procedure main() + + x := Table(1) + write("\nTesting class ",x$class()) + write("Fields:") + every write("\t", x$fieldnames ) + write("Methods:") + every write("\t", x$methodnames ) + write() + x$setElement("world","hello") + write(x$getElement("world")) + write(x$getElement("hello")) + + x := Deque() + write("\nTesting class ",x$class()) + x$push("hello") + x$push("world") + write("My deque is size ",$*x) + every write("give me a ",$!x) + write("A random element is ",$?x) + write("getting ",x$get()," popping ",x$pop()) + + x := List(["Tucson", "Pima", 85721]) + write("\nTesting class ",x$class()) + every write("give me a ",$!x) + +end diff --git a/ipl/packs/idol/buffer.iol b/ipl/packs/idol/buffer.iol new file mode 100644 index 0000000..52cb4f7 --- /dev/null +++ b/ipl/packs/idol/buffer.iol @@ -0,0 +1,132 @@ +class buffer(public filename,text,index) + # read a buffer in from a file + method read() + f := open(self.filename,"r") | fail + self$erase() + every put(self.text,!f) + close(f) + return + end + # write a buffer out to a file + method write() + f := open(self.filename,"w") | fail + every write(f,!self.text) + close(f) + end + # insert a line at the current index + method insert(s) + if self.index = 1 then { + push(self.text,s) + } else if self.index > *self.text then { + put(self.text,s) + } else { + self.text := self.text[1:self.index]|||[s]|||self.text[self.index:0] + } + self.index +:= 1 + return + end + # delete a line at the current index + method delete() + if self.index > *self.text then fail + rv := self.text[self.index] + if self.index=1 then pull(self.text) + else if self.index = *self.text then pop(self.text) + else self.text := self.text[1:self.index]|||self.text[self.index+1:0] + return rv + end + # move the current index to an arbitrary line + method goto(l) + if (1 <= l) & (l <= *self.text+1) then return self.index := l + end + # return the current line and advance the current index + method forward() + if self.index > *self.text then fail + rv := self.text[self.index] + self.index +:= 1 + return rv + end + # place the buffer's text into a contiguously allocated list + method linearize() + tmp := list(*self.text) + every i := 1 to *tmp do tmp[i] := self.text[i] + self.text := tmp + end + method erase() + self.text := [ ] + self.index := 1 + end + method size() + return *(self.text) + end +initially + if \ (self.filename) then { + if not self$read() then self$erase() + } else { + self.filename := "*scratch*" + self.erase() + } +end + + +class buftable : buffer() + method read() + self$buffer.read() + tmp := table() + every line := !self.text do + line ? { tmp[tab(many(&ucase++&lcase))] := line | fail } + self.text := tmp + return + end + method lookup(s) + return self.text[s] + end +end + + +class bibliography : buftable() +end + + +class spellChecker : buftable(parentSpellChecker) + method spell(s) + return \ (self.text[s]) | (\ (self.parentSpellChecker))$spell(s) + end +end + + +class dictentry(word,pos,etymology,definition) + method decode(s) # decode a dictionary entry into its components + s ? { + self.word := tab(upto(';')) + move(1) + self.pos := tab(upto(';')) + move(1) + self.etymology := tab(upto(';')) + move(1) + self.definition := tab(0) + } + end + method encode() # encode a dictionary entry into a string + return self.word||";"||self.pos||";"||self.etymology||";"||self.definition + end +initially + if /self.pos then { + # constructor was called with a single string argument + self$decode(self.word) + } +end + +class dictionary : buftable() + method read() + self$buffer.read() + tmp := table() + every line := !self.text do + line ? { tmp[tab(many(&ucase++&lcase))] := dictentry(line) | fail } + self.text := tmp + end + method write() + f := open(b.filename,"w") | fail + every write(f,(!self.text)$encode()) + close(f) + end +end diff --git a/ipl/packs/idol/buftest.iol b/ipl/packs/idol/buftest.iol new file mode 100644 index 0000000..499b61c --- /dev/null +++ b/ipl/packs/idol/buftest.iol @@ -0,0 +1,19 @@ +# buffer classes' tests + +procedure main(args) + if *args=0 then stop("usage: buftest cp file1 file2") + every i := 1 to *args do { + case args[i] of { + "cp": { + cp(args) + } + } + } +end +procedure cp(args) + b1 := buffer(args[2]) + b2 := buffer(args[3]) + b2$erase() + while s:=b1$forward() do b2$insert(s) + b2$write() +end diff --git a/ipl/packs/idol/builtins.iol b/ipl/packs/idol/builtins.iol new file mode 100644 index 0000000..36403da --- /dev/null +++ b/ipl/packs/idol/builtins.iol @@ -0,0 +1,170 @@ +# %W% %G% +# +# Builtin Icon objects, roughly corresponding to the language builtins. +# (These are not builtin to the Idol interpreter!) +# +# Taxonomy of builtin types: +# +# __Object___ +# _-' `-_ +# _-' `-_ +# Collection Atom_ +# / | \ _' `-. +# Stack Queue Vector _-' Number +# \ / / | \ _-' / \ +# Deque / | \ _' Integer Real +# \ / | \ / +# List Table String +# +# + +# +# this is the Smalltalk-style ideal root of an inheritance hierarchy. +# add your favorite methods here. +# +class Object() + # return the class name as a string + method class() + return image(self)[8:find("_",image(self))] + end + # generate the field names as strings + method fieldnames() + i := 1 + every s := name(!(self.__state)) do { + if i>2 then s ? { tab(find(".")+1); suspend tab(0) } + i +:= 1 + } + end + # generate the method names as strings + method methodnames() + every s := name(!(self.__methods)) do { + s ? { tab(find(".")+1); suspend tab(0) } + } + end +end + +# Collections support Icon's *?! operators +class Collection : Object (theCollection) + method size() + return *self.theCollection + end + method foreach() + suspend !self.theCollection + end + method random() + return ?self.theCollection + end +end + +# Vectors have the ability to access individual elements +class Vector : Collection() + method getElement(i) + return self.theCollection[i] + end + method setElement(i,v) + return self.theCollection[i] := v + end +end + +class Table : Vector(initialvalue,theCollection) +initially + self.theCollection := table(self.initialvalue) +end + +# +# The field theCollection is explicitly named so that subclasses of Stack +# and Queue use these automatic initializations. The / operator is used +# to reduce the number of throw-away list allocations for subclasses which +# >don't< inherit theCollection from Stack or Queue (e.g. class List). +# It also allows initialization by constructor. If one wanted to +# guarantee that all Stacks start out empty but still allow class List +# to be explicitly intitialized, one could remove the / here, and name +# theCollection in class List, causing its initially section to override +# the superclass with respect to the field theCollection. I choose here +# to maximize code sharing rather than protecting my Stack class. +# +# When allowing initialization by constructor one might consider +# checking the type of the input to guarantee it conforms to the +# type expected by the class. +# +class Stack : Collection(theCollection) + method push(value) + push(self.theCollection,value) + end + method pop() + return pop(self.theCollection) + end +initially + /self.theCollection := [] +end + +class Queue : Collection(theCollection) + method get() + return get(self.theCollection) + end + method put(value) + put(self.theCollection,value) + end +initially + /self.theCollection := [] +end + +# Deques are a first example of multiple inheritance. +class Deque : Queue : Stack() +end + +# +# List inherits Queue's theCollection initialization, because Queue is the +# first class on List's (transitively closed) superclass list to name +# theCollection explicitly +# +class List : Deque : Vector() + method concat(l) + return List(self.theCollection ||| l) + end +end + +class Atom : Object(public val) + method asString() + return string(self.val) + end + method asInteger() + return integer(self.val) + end + method asReal() + return real(self.val) + end +end + +class Number : Atom () + method plus(n) + return self.val + n$val() + end + method minus(n) + return self.val - n$val() + end + method times(n) + return self.val * n$val() + end + method divide(n) + return self.val / n$val() + end +end + +class Integer : Number() +initially + if not (self.val := integer(self.val)) then + stop("can't make Integer from ",image(self.val)) +end + +class Real : Number() +initially + if not (self.val := real(self.val)) then + stop("can't make Real from ",image(self.val)) +end + +class String : Vector : Atom() + method concat(s) + return self.theCollection || s + end +end diff --git a/ipl/packs/idol/consttst.iol b/ipl/packs/idol/consttst.iol new file mode 100644 index 0000000..f54af3d --- /dev/null +++ b/ipl/packs/idol/consttst.iol @@ -0,0 +1,12 @@ +const foo := 1 +global barfoo +procedure baz() + barfoo := "OK" +end +procedure main() + baz() + bar1 := "gag!" + write(foo) + write(barfoo) + write("foo") +end diff --git a/ipl/packs/idol/events.iol b/ipl/packs/idol/events.iol new file mode 100644 index 0000000..9f07d2f --- /dev/null +++ b/ipl/packs/idol/events.iol @@ -0,0 +1 @@ +const E_Tick := ".", E_Line := "_", E_Mask := '._' diff --git a/ipl/packs/idol/fraction.iol b/ipl/packs/idol/fraction.iol new file mode 100644 index 0000000..54a2794 --- /dev/null +++ b/ipl/packs/idol/fraction.iol @@ -0,0 +1,19 @@ +class fraction(n,d) + method n() + return self.n + end + method d() + return self.d + end + method times(f) + return fraction(self.n * f$n(), self.d * f$d()) + end + method asString() + return self.n||"/"||self.d + end + method asReal() + return real(self.n) / self.d + end +initially + if self.d=0 then stop("fraction: denominator=0") +end diff --git a/ipl/packs/idol/globtest.iol b/ipl/packs/idol/globtest.iol new file mode 100644 index 0000000..f7652e4 --- /dev/null +++ b/ipl/packs/idol/globtest.iol @@ -0,0 +1,8 @@ +global here, # here + are, # are + some, # some + globals # globals + +procedure main() + write("hi there") +end diff --git a/ipl/packs/idol/ictest.iol b/ipl/packs/idol/ictest.iol new file mode 100644 index 0000000..c9ef6de --- /dev/null +++ b/ipl/packs/idol/ictest.iol @@ -0,0 +1,11 @@ +class ictester() + method classmethod() + write("hello, world") + end +end + +procedure main() + x := ictester() + x$classmethod() + ictester_classmethod(x) +end diff --git a/ipl/packs/idol/idol.1 b/ipl/packs/idol/idol.1 new file mode 100644 index 0000000..d81d43e --- /dev/null +++ b/ipl/packs/idol/idol.1 @@ -0,0 +1,134 @@ +.TH IDOL 1 "10 March 1991" +.UC 4 +.SH NAME +idol \- Icon-Derived Object Language +.SH SYNOPSIS +.B idol +[ +.B option... +] +mainfile otherfiles +[ +.B \-x +arguments +] +.SH DESCRIPTION +.PP +.I Idol +is an object-oriented preprocessor for Version 8+ Icon. +It is a front-end for +.I icont(1) +; typically one invokes idol on +a source file (extension .iol) which is translated into an +Icon source file (extension .icn) which is translated into a +file suitable for interpretation by the Icon interpreter. +.PP +On systems with directories, Idol typically stores its generated class +library code in a separate directory from the source code. If the +environment variable IDOLENV is defined, Idol uses this directory for +generated code. If no IDOLENV is defined, Idol creates a subdirectory +named idolcode.env, and removes it after successful compilation +if the creation occured for a single source file. +.PP +Producing an executable is skipped when the first file on the +list contains only classes and no Icon entities. Idol uses an +Icon translator selected by the environment variable ICONT, if +it is present. +.PP +The +.B \-c +option suppresses the linking phase normally done by +.I Icont. +.PP +The +.B \-t +option suppresses +.B all +translation by +.I Icont; +it is useful on systems for which Icon does not support the +.br +.B system\(\) +function. +.PP +The +.B \-s +option suppresses removal of +.B \.icn +files after translation by +.I Icont; +normally they are deleted after a successful translation. +.PP +The +.B \-quiet +option suppresses most Idol-specific console messages. +.PP +The +.B \-strict +option causes +.I Idol +to generate code which is paranoid about ensuring encapsulation. +.PP +The +.B \-ic +option causes +.I Idol +to generate code that is +.I Icon-compatible. +The code will be slightly slower, but allows method invocation using +a traditional Icon procedure call. Such procedure calls are of the form +class_method(o,args...). Inherited methods cannot currently be so +invoked, the class that defines the method must be explicitly named in +the procedure call. +.PP +The +.B \-version +option causes +.I Idol +to print out its version and date of creation, and then exit. +.PP +The second and following files on the command line may include +extensions +.B \.icn +, +.B \.u1 +, and +.B \.cl\. +The first two Idol treats as +Icon source code which should be translated and linked into the +resulting executable. Files with extension +.B \.cl +are treated as class names which are linked into the resulting executable. +Class names are case sensitive; Deque.cl is a different class than deque.cl. +If the operating system does not support case sensitive filenames, such +class names will not coexist peacefully. +.PP +.SH AUTHOR +.PP +Clinton Jeffery, cjeffery@cs.arizona.edu +.PP +.SH FILES +.PP +.nf +idol The Idol translator itself. +.br +prog.iol Idol source files +.br +prog.icn Icon code (non-classes) from prog.iol +.br +idolcode.env/i_object.* Icon code for the Idol object type +.br +idolcode.env/classname.icn Icon files generated for each class +.br +idolcode.env/classname.u[12] Translated class files +.br +idolcode.env/classname Class specification/interface +.fi +.SH SEE ALSO +.PP +.br +"Programming in Idol: An Object Primer" +.br +(U of Arizona Dept of CS Technical Report #90-10) +.br +serves as a user's guide and reference manual for Idol diff --git a/ipl/packs/idol/idol.bat b/ipl/packs/idol/idol.bat new file mode 100644 index 0000000..3dabd3f --- /dev/null +++ b/ipl/packs/idol/idol.bat @@ -0,0 +1,2 @@ +iconx idol %1 %2 %3 %4 %5 %6 %7 %8 %9
+idolt
diff --git a/ipl/packs/idol/idol.hqx b/ipl/packs/idol/idol.hqx new file mode 100644 index 0000000..0da0787 --- /dev/null +++ b/ipl/packs/idol/idol.hqx @@ -0,0 +1,179 @@ +----------------------------------------------------------------- +(This file must be converted with BinHex 4.0) + + +:#de39dPNEf`ZFfPd!&0*9#&6593K!*!%#aJ!N!3jU90*9#%!!`!!#aKb6'&e!I) + + +!N!-@!E!#!JKTC'pX,Qe`Ffi!N"C6"J#3&!*K!*!%rj!%9%9B9%e38b!"!+M[3Z' + + +Sp`Y3!!!"V!#3!r)!!!%T!*!$XP-9Gm-!N!BeZ!!!"!JSd!e"J`&p!)JJ3&4!EQ3 + + +!-'MiN!!0J!-#2$hN"-#"J&)235&)3qB0'aGYi-aj)i!JP5*BU$5"-J8%`48!r"& + + +d#9-Q6CX"FHVF5E4S3&6[K)3M+#pJ!&EGF!&J)F"9`'lF!&33m1SU1`!HZ!EdaJ# + + +!!3'`aR+BLRBX%+d#BSf&!MEZ@$KQ"FJD#`J!#VeM5F'G0CB@!!i##!2`4Lf[iFA + + +Nr!Tir#hJePS"[d%i,!!cJ'mdkYl+M)BJ%J!*QVaa%fE-'`!D!*`3Z#pYJ(pV3a$ + + +8R3#!lKDqc3*!!)!4!!S"'JRS8IaimZ@SlLfJHj9JYjd$#ATSMP`jFq2GPaXG,j! + + +!B!#%!0!V2$B!h30Q"0FU"$"cLT6b#JDdqrG[r!"ir"(%"!$*G-%')aU-!!'L#C3 + + +V)+DJ+F1'$BJjBq5NJ8-("*dh)168F3-L$CNhE!3f5$2QM4Xm)2D3!$6Cab0)(5l + + +CZ##*FSm)1'(NK'P6KNiC1A0%p!("K`m)@`d)%N3a*Sa20dl,T&cTTZ9(0M#[ZLM + + +CTNdB0f6QJ0J"JJc$RP*9PU`D-b[)V@qkIJdl&N3C2'NUaNJa8LYAVf$&&J@"`L` + + +EY"hpaJ9-PqcG[#$f0M#-1#CFZB%E2+i)S`%#!Ja0B@YPCQPXC5jYF(F!N"0Fe!# + + +3%4B!!!6M!*!%rj!%9%9B9'4[Ff%"!+MfZ3USp`Sk!!!"V!!!!9!!!!&-!*!$aYa + + +BHYi!N!B#Q!!!"!JSd!e"J`&p"(((cji3###S`%!"`!`5B#m!)((6d%NV!lVJ!-L + + +iX@'$*Q(@P$'6KNdC%'2H`-NMJ##9)PLSN!"j-bI-3!!3J!DmQA0Rcjp"Ja*FbT3 + + +T+RZj&!3-!'8UUihpl'hmTe82!')[$Va`mBqI%ehiq2%!m13G!!TQ5,4Smdr12ha + + +q0,VaTp809kci`SkpHaDIYE9Yh`SjSX5)'5!L-ilejfmMAim!G#a1c!!-!4J(T"a + + +KF!3!!MB+&[*9!N1N'ABJ@[`6")eA3#cY*#mJL!4!JLC[h)5*#H!0'a"TGV*T%bD + + +0'aGeBS#SibB0(ZM5N`-`B"V!@K)"ZJRSi4d!H2%p80e6S)0J&IG,I`Ed82lmq2V + + +KlcIG2j9J!)3!!1J$!-F-J%i$l3A%!3!$!Y!%&&0))4!!#Jc3cMrrm$F!2"J5a!3 + + +!bA$"##-DM!$4*-bD-QE5X#N$`X`E15$'['N$4f%D0fG!*#(cKJf)1Ql)P)(B"-S + + +9J3dDT1()aN@D-AK!%!1aXQ1$"(,+Z!R6KQ',2$4C"ZhS%QE+QKjR)RACF5LE0Q% + + +ZZUJ6!`6&1e1V)KAcjJfGQeZldR&U&3j@UNkK5U8+PU8,L@fJKTac8q4#1JbA`T9 + + +,KUj+PPbpbR3DQ%j40fA2aJ!VdFhBX)+[CNdT'He-b5rG-(lM'%5,-BQ2XP6V*ZY + + +JT+32Eqlm1@e8c3)#"fe`GbjTBfjP,R9ZDAJ!N"*dK`#3%!*K!*!)rj!%9%9B9%e + + +38b!"!+M[2VkU'm)V!!!"V!!!"l!!!!%%!!!%`FBZUki!N!C8Q3!!"!JSd!e"J`& + + +p"*bJ!X+3!#pMf)5C-mG)QM*Xb-aa88I''!%%U46"3LA0Q!0Yi0aaBG)0b)!L56D + + +"-JA%3!!8"S!K#!!,(jJMUFbXH62R6Tj)N`C%pFk(Vi!(B!8-`%UT8JJ%'5Ti11D + + +0QcPd`VLK!q!PJ*K8V#DG%!MTR)!'e#jp&m34db0Kj1S&S+bI`,ekN3")d-4VQ+i + + +!dSap-`F0L*PA'S`!%B4-'$KdbT!!!@&'cTXf!1)L!)!(!)B!M36d)'dDY@T9'i5 + + +YJ#S93&5H0`0kB(dkpHV5[98$*TJl!%)!ahd%L(8"N34H"$N!8!KJU*5r#JDdqrI + + +2kJ"ih!Nb#6!,$L-M'S`!!36&L"4Yi0aaN@D-Q`3aA03!%32'#aNiAZ5B)C!!S%' + + +%#KNkK1L#"SJD,e$QJ0(abC3@Fq#8'C2'6%-3Bpk3!#N$`X`E15#DK+(TKXkE1@L + + +#3VR5-3LC-($SP#(68mkE0L$UZ%Q$4k3E%',bJ"L#*S`F0QAQJ'!5CXh4MNedeN` + + +c&DaB)@r%J!L#&NmB0cZ"9VbBFD2!"QIBj!h$"N6$0dAI4'94aSdG&R2bc(QcTN% + + +$1&E(6+dMKfFEcCUPYN%a*d8$%)l0J1#LZ!j91QJUJlJM*ie8eUjKPkC$qQ[Q1DU + + +"0kK-aM2S0k,*N!$QD41YQc"YbV#QM)G1F""UqI$4d@0fQHk[33`[$RijB-m$Di, + + +!66f0GH`meCC9HekUQcPT3!C#Ir2PpY9kFRa&Adrf9BBI#'M0S4Cp(I9A'B#3!,% + + +!`K[dbA&('R03&iCp,R`@fQLP-BL@94aZepphmXfa43XJU%#J$L$!d!8)2C4()(d + + +(PN&FJZ"Y%3-)10*SBhGGZ0HFLG#Kb"0[[U99KaKXT1(''XV"4U98@@k*3Q9fL#I + + +#&b+)ejU6cTdSABTN`K%'ELK8jf"fhb(i&CPQSLQHRGGPafC!!bAa(af-X6&RJ'k + + +81&!9)HT(PaaQMB&'3ibTQ&CUC@!Pi'ECJFGT'fUa9JC2@[U@"Q0Tk&''D`%p&pe + + +dMKfD+!TQRE'QPlhp*S+Kb#@Uj4Q1NI&'Bf5QBC8Ef4@eQfp*J9D'6AL!)!*PPRh + + +R8aed)1QMCC*9KS))DAb4PaScdH(9Y5,F)F*hAfUh,4dXL&"D6R*3PBDaE*JV"VT + + +Md)(#&em%+a8,"'H(QdkY[C[H')U&@1FEh'T,FEINJ@##'h@``FE$C$a@&!TEN!$ + + +V,m"dL0#&Dmbe'H@E2'QPCE!HibU(VYm0j!D(ML@%9V058C@(N!"X3MPVLQfdG5S + + +HfZ8k"`YTI(FH6aNl[88D6F)QRmJ#6jd#Ml-GaeQ"ZZf4(Qb`RACFFL,XK*C8eSS + + +hYCRVISGfE1Ba23ECAjQG3,cM&U%hYm2Ui(!#CGK4KKaLTH(YJ(U[F+4406S0JV' + + +3!2-NAXBLa-f(e9JhN!#!fU11bE6GD2H4RZV##9PFdB5+LPbR,H`N%f#9GCY63[B + + +Y+Z!EXZelV*eHG33E#PU5AHbai&dCmVe'-DkKI"fLUKCNVaiQUj3iKCc6b-+cBHH + + +Z)&M113JYM#&#HR+3!!SEjq[$P[MLMG[jH!MKMhrj'qAI(0jijHPFjm3c)-[)L8j + + +c3B[8&-Hif$6SI[PVN!"D-0FqYB"JF`'deJAj8%!l("!0b,26e`JSJR9j4QZbf4d + + +F`0B#'I"02DiM%JJ'dS*ZYD!&2YLI'dl3,6T3kMq+JYZFbZHap'cYH`*c@VhH"6B + + +ZL+dcX!%5#%JhZp@dV3a[idQDq&$"2-A3$8AE(XaNPbSkV#T,VN)"M*!!+"Q-C6" + + +q(H6F%1$ia-Ha"$DeS8V'0YDaMlA-D0aE@kHk"#(SC-S-B)50`@jL"L0ZaBbC-Y[ + + +G%2NiF[(,"EY,'Q$Q!%IBb#CMiA*$RGa3,hH0%$a'JF1iK[!A(QlSGYCL!5,VeC1 + + +IE)KEF1#@`qi'1$28+d6GQJNDq"H$AB+!GE[TPE``im8K'8FcR'%6HpX!!!: + + + diff --git a/ipl/packs/idol/idol.iol b/ipl/packs/idol/idol.iol new file mode 100644 index 0000000..f75ee52 --- /dev/null +++ b/ipl/packs/idol/idol.iol @@ -0,0 +1,863 @@ +# +# global variables +# +global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha +global classes,comp,exec,strict,links,imports,loud,compiles,compatible,ct +# +# gencode first generates specifications for all defined classes +# It then imports those classes' specifications which it needs to +# compute inheritance. Finally, it writes out all classes' .icn files. +# +procedure gencode() + if \loud then write("Class import/export:") + # + # export specifications for each class + # + every cl := classes$foreach_t() do cl$writespec() + # + # import class specifications, transitively + # + repeat { + added := 0 + every super:= ((classes$foreach_t())$foreachsuper() | !imports) do{ + if /classes$lookup(super) then { + added := 1 + fname := filename(super) + readinput(envpath(fname),2) + if /classes$lookup(super) then halt("can't import class '",super,"'") + writesublink(fname) + } + } + if added = 0 then break + } + # + # compute the transitive closure of the superclass graph + # + every (classes$foreach_t())$transitive_closure() + # + # generate output + # + if \loud then write("Generating code:") + writesublink("i_object") + every s := !links do writelink(s) + write(fout) + every out := $!classes do { + name := filename(out$name()) + out$write() + put(compiles,name) + writesublink(name) + } + if *compiles>0 then return cdicont(compiles) + else return +end + +# +# a class defining objects resulting from parsing lines of the form +# tag name ( field1 , field2, ... ) +# If the constructor is given an argument, it is passed to self$read +# +class declaration(public name,fields,tag) + # + # parse a declaration string into its components + # + method read(decl) + decl ? ( + (tab(many(white)) | "") , + # get my tag + (self.tag := =("procedure"|"class"|"method"|"record")) , + (tab(many(white)) | "") , + # get my name + (self.name := tab(many(alpha))) , + # get my fields + (tab(find("(")+1)), + (tab(many(white)) | "") , + ((self.fields := classFields())$parse(tab(find(")")))) + ) | halt("declaration/read can't parse decl ",decl) + end + + # + # write a declaration; at the moment, only used by records + # + method write(f) + write(f,self$String()) + end + # + # convert self to a string + # + method String() + return self.tag || " " || self.name || "(" || self.fields$String() || ")" + end +initially + if \self.name then self$read(self.name) +end + +# +# A class for ordinary Icon global declarations +# +class vardecl(s) + method write(f) + write(f,self.s) + end +end + +# +# A class defining the constants for a given scope +# +class constant(t) + method expand(s) + i := 1 + # + # conditions for expanding a constant: + # must not be within a larger identifier nor within a quote + # + while ((i <- find(k <- $!self,s,i)) & ((i=1) | any(nonalpha,s[i-1])) & + ((*s = i+*k-1) | any(nonalpha,s[i+*k])) & + notquote(s[1:i])) do { + val := \ (self.t[k]) | stop("internal error in expand") + s[i +: *k] := val +# i +:= *val + } + return s + end + method foreach() # in this case, we mean the keys, not the values + suspend key(self.t) + end + method eval(s) + if s2 := \ self.t[s] then return s2 + end + method parse(s) + s ? { + k := trim(tab(find(":="))) | fail + move(2) + tab(many(white)) + val := tab(0) | fail + (*val > 0) | fail + self.t [ k ] := val + } + return + end + method append(cd) + every s := cd$parse do self$parse(s) + end +initially + self.t := table() +end + +# +# A class defining a single constant declaration +# +class constdcl : vardecl() + # suspend the individual constant := value strings + method parse() + self.s ? { + tab(find("const")+6) + tab(many(white)) + while s2 := trim(tab(find(","))) do { + suspend s2 + move(1) + tab(many(white)) + } + suspend trim(tab(0)) + } + end +end + +# +# class body manages a list of strings holding the code for +# procedures/methods/classes +# +class body(fn,ln,vars,text) + method read() + self.fn := fName + self.ln := fLine + self.text := [] + while line := readln() do { + put(self.text, line) + line ? { + tab(many(white)) + if ="end" & &pos > *line then return + else if =("local"|"static"|"initial") & any(nonalpha) then { + self.ln +:= 1 + pull(self.text) + / (self.vars) := [] + put(self.vars, line) + } + } + } + halt("body/read: eof inside a procedure/method definition") + end + method write(f) + if \self.vars then every write(f,!self.vars) + if \compatible then write(f," \\self := self.__state") + if \self.ln then + write(f,"#line ",self.ln + ((*\self.vars)|0)," \"",self.fn,"\"") + every write(f,$!self) + end + method delete() + return pull(self.text) + end + method size() + return (*\ (self.text)) | 0 + end + method foreach() + if t := \self.text then suspend !self.text + end +end + +# +# a class defining operations on classes +# +class class : declaration (supers,methods,text,imethods,ifields,glob) + # imethods and ifields are all lists of these: + record classident(class,ident) + + method read(line,phase) + self$declaration.read(line) + self.supers := idTaque(":") + self.supers$parse(line[find(":",line)+1:find("(",line)] | "") + self.methods:= taque() + self.text := body() + while line := readln("wrap") do { + line ? { + tab(many(white)) + if ="initially" then { + self.text$read() + if phase=2 then return + self.text$delete() # "end" appended manually during writing after + # generation of the appropriate return value + return + } else if ="method" then { + decl := method(self.name) + decl$read(line,phase) + self.methods$insert(decl,decl$name()) + } else if ="end" then { + # "end" is tossed here. see "initially" above + return + } else if ="procedure" then { + decl := method("") + decl$read(line,phase) + /self.glob := [] + put(self.glob,decl) + } else if ="global" then { + /self.glob := [] + put(self.glob,vardecl(line)) + } else if ="record" then { + /self.glob := [] + put(self.glob,declaration(line)) + } else if upto(nonwhite) then { + halt("class/read expected declaration on: ",line) + } + } + } + halt("class/read syntax error: eof inside a class definition") + end + + # + # Miscellaneous methods on classes + # + method has_initially() + return $*self.text > 0 + end + method ispublic(fieldname) + if self.fields$ispublic(fieldname) then return fieldname + end + method foreachmethod() + suspend $!self.methods + end + method foreachsuper() + suspend $!self.supers + end + method foreachfield() + suspend $!self.fields + end + method isvarg(s) + if self.fields$isvarg(s) then return s + end + method transitive_closure() + count := $*self.supers + while count > 0 do { + added := taque() + every sc := $!self.supers do { + if /(super := classes$lookup(sc)) then + halt("class/transitive_closure: couldn't find superclass ",sc) + every supersuper := super$foreachsuper() do { + if / self.supers$lookup(supersuper) & + /added$lookup(supersuper) then { + added$insert(supersuper) + } + } + } + count := $*added + every self.supers$insert($!added) + } + end + # + # write the class declaration: if s is "class" write as a spec + # otherwise, write as a constructor + # + method writedecl(f,s) + writes(f, s," ",self.name) + if s=="class" & ( *(supers := self.supers$String()) > 0 ) then + writes(f," : ",supers) + writes(f,"(") + rv := self.fields$String(s) + if *rv > 0 then rv ||:= "," + if s~=="class" & *(\self.ifields)>0 then { # inherited fields + every l := !self.ifields do rv ||:= l.ident || "," + if /(superclass := classes$lookup(l.class)) then + halt("class/resolve: couldn't find superclass ",sc) + if superclass$isvarg(l.ident) then rv := rv[1:-1]||"[]," + } + writes(f,rv[1:-1]) + write(f,,")") + end + method writespec(f) # write the specification of a class + f := envopen(filename(self.name),"w") + self$writedecl(f,"class") + every ($!self.methods)$writedecl(f,"method") + if self$has_initially() then write(f,"initially") + write(f,"end") + close(f) + end + + # + # write out the Icon code for this class' explicit methods + # and its "nested global" declarations (procedures, records, etc.) + # + method writemethods() + f:= envopen(filename(self.name,".icn"),"w") + every ($!self.methods)$write(f,self.name) + + if \self.glob & *self.glob>0 then { + write(f,"#\n# globals declared within the class\n#") + every i := 1 to *self.glob do (self.glob[i])$write(f,"") + } + close(f) + end + + # + # write - write an Icon implementation of a class to file f + # + method write() + f:= envopen(filename(self.name,".icn"),"a") + # + # must have done inheritance computation to write things out + # + if /self.ifields then self$resolve() + + # + # write a record containing the state variables + # + writes(f,"record ",self.name,"__state(__state,__methods") # reserved fields + rv := "," + rv ||:= self.fields$idTaque.String() # my fields + if rv[-1] ~== "," then rv ||:= "," + every s := (!self.ifields).ident do rv ||:= s || "," # inherited fields + write(f,rv[1:-1],")") + + # + # write a record containing the methods + # + writes(f,"record ",self.name,"__methods(") + rv := "" + + every s := ((($!self.methods)$name()) | # my explicit methods + self.fields$foreachpublic() | # my implicit methods + (!self.imethods).ident | # my inherited methods + $!self.supers) # super.method fields + do rv ||:= s || "," + + if *rv>0 then rv[-1] := "" # trim trailling , + write(f,rv,")") + + # + # write a global containing this classes' operation record + # along with declarations for all superclasses op records + # + writes(f,"global ",self.name,"__oprec") + every writes(f,", ", $!self.supers,"__oprec") + write(f) + + # + # write the constructor procedure. + # This is a long involved process starting with writing the declaration. + # + self$writedecl(f,"procedure") + write(f,"local self,clone") + + # + # initialize operation records for this and superclasses + # + write(f,"initial {\n", + " if /",self.name,"__oprec then ",self.name,"initialize()") + if $*self.supers > 0 then + every (super <- $!self.supers) ~== self.name do + write(f," if /",super,"__oprec then ",super,"initialize()\n", + " ",self.name,"__oprec.",super," := ", super,"__oprec") + write(f," }") + + # + # create self, initialize from constructor parameters + # + writes(f," self := ",self.name,"__state(&null,",self.name,"__oprec") + every writes(f,",",$!self.fields) + if \self.ifields then every writes(f,",",(!self.ifields).ident) + write(f,")\n self.__state := self") + + # + # call my own initially section, if any + # + if $*self.text > 0 then write(f," ",self.name,"initially(self)") + + # + # call superclasses' initially sections + # + if $*self.supers > 0 then { + every (super <- $!self.supers) ~== self.name do { + if (classes$lookup(super))$has_initially() then { + if /madeclone := 1 then { + write(f," clone := ",self.name,"__state()\n", + " clone.__state := clone\n", + " clone.__methods := ",self.name,"__oprec") + } + write(f," # inherited initialization from class ",super) + write(f," every i := 2 to *self do clone[i] := self[i]\n", + " ",super,"initially(clone)") + every l := !self.ifields do { + if l.class == super then + write(f," self.",l.ident," := clone.",l.ident) + } + } + } + } + + # + # return the pair that comprises the object: + # a pointer to the instance (__mystate), and + # a pointer to the class operation record + # + write(f," return idol_object(self,",self.name,"__oprec)\n", + "end\n") + + # + # write out class initializer procedure to initialize my operation record + # + write(f,"procedure ",self.name,"initialize()") + writes(f," initial ",self.name,"__oprec := ",self.name,"__methods") + rv := "(" + every s := ($!self.methods)$name() do { # explicit methods + if *rv>1 then rv ||:= "," + rv ||:= self.name||"_"||s + } + every me := self.fields$foreachpublic() do { # implicit methods + if *rv>1 then rv ||:= "," # (for public fields) + rv ||:= self.name||"_"||me + } + every l := !self.imethods do { # inherited methods + if *rv>1 then rv ||:= "," + rv ||:= l.class||"_"||l.ident + } + write(f,rv,")\n","end") + # + # write out initially procedure, if any + # + if self$has_initially() then { + write(f,"procedure ",self.name,"initially(self)") + self.text$write(f) + write(f,"end") + } + + # + # write out implicit methods for public fields + # + every me := self.fields$foreachpublic() do { + write(f,"procedure ",self.name,"_",me,"(self)") + if \strict then { + write(f," if type(self.",me,") == ", + "(\"list\"|\"table\"|\"set\"|\"record\") then\n", + " runerr(501,\"idol: scalar type expected\")") + } + write(f," return .(self.",me,")") + write(f,"end") + write(f) + } + + close(f) + + end + + # + # resolve -- primary inheritance resolution utility + # + method resolve() + # + # these are lists of [class , ident] records + # + self.imethods := [] + self.ifields := [] + ipublics := [] + addedfields := table() + addedmethods := table() + every sc := $!self.supers do { + if /(superclass := classes$lookup(sc)) then + halt("class/resolve: couldn't find superclass ",sc) + every superclassfield := superclass$foreachfield() do { + if /self.fields$lookup(superclassfield) & + /addedfields[superclassfield] then { + addedfields[superclassfield] := superclassfield + put ( self.ifields , classident(sc,superclassfield) ) + if superclass$ispublic(superclassfield) then + put( ipublics, classident(sc,superclassfield) ) + } else if \strict then { + warn("class/resolve: '",sc,"' field '",superclassfield, + "' is redeclared in subclass ",self.name) + } + } + every superclassmethod := (superclass$foreachmethod())$name() do { + if /self.methods$lookup(superclassmethod) & + /addedmethods[superclassmethod] then { + addedmethods[superclassmethod] := superclassmethod + put ( self.imethods, classident(sc,superclassmethod) ) + } + } + every public := (!ipublics) do { + if public.class == sc then + put (self.imethods, classident(sc,public.ident)) + } + } + end +end + +# +# a class defining operations on methods and procedures +# +class method : declaration (class,text) + method read(line,phase) + self$declaration.read(line) + self.text := body() + if phase = 1 then + self.text$read() + end + method writedecl(f,s) + decl := self$String() + if s == "method" then decl[1:upto(white,decl)] := "method" + else { + decl[1:upto(white,decl)] := "procedure" + if *(self.class)>0 then { + decl[upto(white,decl)] ||:= self.class||"_" + i := find("(",decl) + decl[i] ||:= "self" || (((decl[i+1] ~== ")"), ",") | "") + } + } + write(f,decl) + end + method write(f) + if self.name ~== "initially" then + self$writedecl(f,"procedure") + self.text$write(f) + self.text := &null # after writing out text, forget it! + end +end + +# +# a class corresponding to an Icon table, with special treatment of empties +# +class Table(t) + method size() + return (* \ self.t) | 0 + end + method insert(x,key) + /self.t := table() + /key := x + if / (self.t[key]) := x then return + end + method lookup(key) + if t := \self.t then return t[key] + return + end + method foreach() + if t := \self.t then every suspend !self.t + end +end + +# +# tabular queues (taques): +# a class defining objects which maintain synchronized list and table reps +# Well, what is really provided are loosely-coordinated list/tables +# +class taque : Table (l) + method insert(x,key) + /self.l := [] + if self$Table.insert(x,key) then put(self.l,x) + end + method foreach() + if l := \self.l then every suspend !self.l + end + method insert_t(x,key) + self$Table.insert(x,key) + end + method foreach_t() + suspend self$Table.foreach() + end +end + +# +# support for taques found as lists of ids separated by punctuation +# constructor called with (separation char, source string) +# +class idTaque : taque(punc) + method parse(s) + s ? { + tab(many(white)) + while name := tab(find(self.punc)) do { + self$insert(trim(name)) + move(1) + tab(many(white)) + } + if any(nonwhite) then self$insert(trim(tab(0))) + } + return + end + method String() + if /self.l then return "" + out := "" + every id := !self.l do out ||:= id||self.punc + return out[1:-1] + end +end + +# +# parameter lists in which the final argument may have a trailing [] +# +class argList : idTaque(public varg) + method insert(s) + if \self.varg then halt("variable arg must be final") + if i := find("[",s) then { + if not (j := find("]",s)) then halt("variable arg expected ]") + s[i : j+1] := "" + self.varg := s := trim(s) + } + self$idTaque.insert(s) + end + method isvarg(s) + if s == \self.varg then return s + end + method String() + return self$idTaque.String() || ((\self.varg & "[]") | "") + end +initially + self.punc := "," +end + +# +# Idol class field lists in which fields may be preceded by a "public" keyword +# +class classFields : argList(publics) + method String(s) + if *(rv := self$argList.String()) = 0 then return "" + if /s | (s ~== "class") then return rv + if self$ispublic(self.l[1]) then rv := "public "||rv + every field:=self$foreachpublic() do rv[find(","||field,rv)] ||:= "public " + return rv + end + method foreachpublic() + if \self.publics then every suspend !self.publics + end + method ispublic(s) + if \self.publics then every suspend !self.publics == s + end + method insert(s) + s ? { + if ="public" & tab(many(white)) then { + s := tab(0) + /self.publics := [] + put(self.publics,s) + } + } + self$argList.insert(s) + end +initially + self.punc := "," +end + +# +# procedure to read a single Idol source file +# +procedure readinput(name,phase,ct2) + if \loud then write("\t",name) + fName := name + fLine := 0 + fin := sysopen(name,"r") + ct := \ct2 | constant() + while line := readln("wrap") do { + line ? { + tab(many(white)) + if ="class" then { + decl := class() + decl$read(line,phase) + if phase=1 then { + decl$writemethods() + classes$insert(decl,decl$name()) + } else classes$insert_t(decl,decl$name()) + } + else if ="procedure" then { + if comp = 0 then comp := 1 + decl := method("") + decl$read(line,phase) + decl$write(fout,"") + } + else if ="record" then { + if comp = 0 then comp := 1 + decl := declaration(line) + decl$write(fout,"") + } + else if ="global" then { + if comp = 0 then comp := 1 + decl := vardecl(line) + decl$write(fout,"") + } + else if ="const" then { + ct$append ( constdcl(line) ) + } + else if ="method" then { + halt("readinput: method outside class") + } + else if ="#include" then { + savedFName := fName + savedFLine := fLine + savedFIn := fin + tab(many(white)) + readinput(tab(if ="\"" then find("\"") else many(nonwhite)), + phase,ct) + fName := savedFName + fLine := savedFLine + fin := savedFIn + } + } + } + close(fin) +end + +# +# filter the input translating $ references +# (also eats comments and trims lines) +# +procedure readln(wrap) + count := 0 + prefix := "" + while /finished do { + + if not (line := read(fin)) then fail + fLine +:= 1 + if match("#include",line) then return line + line[ 1(x<-find("#",line),notquote(line[1:x])) : 0] := "" + line := trim(line,white) +# line := selfdot(line) + x := 1 + while ((x := find("$",line,x)) & notquote(line[1:x])) do { + z := line[x+1:0] ||" " # " " is for bal() + case line[x+1] of { + # + # IBM 370 digraphs + # + "(": line[x+:2] := "{" + ")": line[x+:2] := "}" + "<": line[x+:2] := "[" + ">": line[x+:2] := "]" + # + # Invocation operators $! $* $@ $? (for $$ see below) + # + "!"|"*"|"@"|"?": { + z ? { + move(1) + tab(many(white)) + if not (id := tab(many(alphadot))) then { + if not match("(") then halt("readln can't parse ",line) + if not (id := tab(&pos<bal())) then + halt("readln: cant bal ",&subject) + } + Op := case line[x+1] of { + "@": "activate" + "*": "size" + "!": "foreach" + "?": "random" + } + count +:= 1 + line[x:0] := + "(__self"||count||" := "||id||").__methods."|| + Op||"(__self"||count||".__state)"||tab(0) + } + } + # + # x $[ y ] shorthand for x$index(y) + # + "[": { + z ? { + if not (middle := tab((&pos<bal(&cset,'[',']'))-1)[2:0]) then + halt("readln: can't bal([) ",&subject) + tail := tab(0)|"" + line := line[1:x]||"$index("||middle||")"||(tab(0)|"") + } + } + default: { + # + # get the invoking object. + # + reverse(line[1:x])||" " ? { + tab(many(white)) + if not (id := reverse(tab(many(alphadot)))) then { + if not match(")") then halt("readln: can't parse") + if not (id := reverse(tab(&pos<bal(&cset,')','(')))) + then halt("readln: can't bal ",&subject) + } + objlen := &pos-1 + } + count +:= 1 + front := "(__self"||count||" := "||id||").__methods." + back := "__self"||count||".__state" + + # + # get the method name + # + z ? { + ="$" + tab(many(white)) + if not (methodname := tab(many(alphadot))) then + halt("readln: expected a method name after $") + tab(many(white)) + methodname ||:= "(" + if ="(" then { + tab(many(white)) + afterlp := &subject[&pos] + } + else { + afterlp := ")" + back ||:= ")" + } + methlen := &pos-1 + } + if line[x+1] == "$" then { + c := if afterlp[1] ~== ")" then "" else "[]" + methodname[-1] := "!(" + back := "["||back||"]|||" + } else { + c := if (\afterlp)[1] == ")" then "" else "," + } + line[x-objlen : (((*line>=(x+methlen+1))|0)\1)] := + front || methodname || back || c + } + } # case + } # while there's a $ to process + if /wrap | (prefix==line=="") then finished := line + else { + prefix ||:= line || " " # " " is for bal() + prefix ? { + # we are done if the line is balanced wrt parens and + # doesn't end in a continuation character (currently just ,) + if ((*prefix = bal()) & (not find(",",prefix[-2]))) then + finished := prefix[1:-1] + } + } + } # while / finished + return ct$expand(finished) +end diff --git a/ipl/packs/idol/idol.man b/ipl/packs/idol/idol.man new file mode 100644 index 0000000..d277e71 --- /dev/null +++ b/ipl/packs/idol/idol.man @@ -0,0 +1,58 @@ +NAME + idol - Icon-Derived Object Language + +SYNOPSIS + idol [ option ... ] mainfile otherfiles... [-x arguments] + +DESCRIPTION + Idol is an object-oriented preprocessor for Version 8+ Icon. + It is a front-end for icont(1); typically one invokes idol on + a source file (extension .iol) which is translated into an + Icon source file (extension .icn) which is translated into a + file suitable for interpretation by the Icon interpreter. + + On systems with directories, Idol typically stores its generated + class library code in a separate directory from the source code. + If the environment variable IDOLENV is defined, Idol uses this + directory for generated code. If no IDOLENV is defined, Idol + creates a subdirectory named idolcode.env, and removes it after + successful compilation if the creation occurred for a single + source file. + + Producing an executable is skipped when the first file on the + list contains only classes and no Icon entities. Idol uses an + Icon translator selected by the environment variable ICONT, + if it is present. + + The following options are recognized by idol: + + -c Suppress the linking phase + -t Suppress all translation by icont + -s Suppress removal of .icn files after translation by icont + -quiet Suppress most Idol-specific console messages + -strict Generate code that is paranoid about ensuring encapsulation + -version Print out the version of Idol and its date of creation + -ic Generate code to create Icon-compatible class libraries + + The second and following files on the command line may include + extensions .icn, .u1, and .cl. The first two Idol treats as + Icon source code which should be translated and linked into the + resulting executable. Files with extension .cl are treated as + class names which are linked into the resulting executable. + If no extension is given, Idol attempts to find the desired + source file by appending .iol, .icn, .u1, or .cl in that order. + +FILES + + prog.iol : source file + prog.icn : code generated for non-classes in prog.iol + idolcode.env/i_object.* : Icon code for the universal object type + idolcode.env/classname.icn : Icon files are generated for each class + idolcode.env/classname.u[12] : translated class files + idolcode.env/classname : class specification/interface + +SEE ALSO + + "Programming in Idol: An Object Primer" + (U of Arizona Dept of CS Technical Report #90-10) + serves as user's guide and reference manual for Idol diff --git a/ipl/packs/idol/idol.txt b/ipl/packs/idol/idol.txt new file mode 100644 index 0000000..94ef0e1 --- /dev/null +++ b/ipl/packs/idol/idol.txt @@ -0,0 +1,1325 @@ + + + + Programming in Idol: An Object Primer + + Clinton L. Jeffery + + January 25, 1990; Last revised March 4, 1991 + +Idol is an object-oriented extension and environment for the Icon +programming language. This document describes Idol in two parts. +The first part presents Idol's object-oriented programming concepts +as an integral tool with which a programmer maps a good program +design into a good implementation. As such, it serves as the +"user's guide" for Idol's extensions to Icon. Idol's +object-oriented programming facilities are viewed within the +broader framework of structured programming and modular design +in general. Idol's precise syntax and semantics are detailed +in the second part, "An Icon-Derived Object Language", which +serves as a reference manual. + + + + + + Object-Oriented Programming After a Fashion + +Object-oriented programming means different things to different people. +In Idol, object-oriented programming centers around encapsulation, +inheritance, and polymorphism. These key ideas are shared by most +object-oriented languages as well as many languages that are not +considered object-oriented. This paper introduces these ideas and +illustrates their use in actual code. Idol is relevant in this +discussion because programming concepts are more than mental +exercises; they are mathematical notations by which programmers share +their knowledge. + +Object-oriented programming can be done in Smalltalk, C++, or +assembler language for that matter, but this does not mean these +programming notations are equally desirable. Assembler languages +are not portable. For most programmers, Smalltalk uses an alien +notation; Smalltalk programs also share the flaw that they do not +work well in environments such as UNIX and DOS that consist of +interacting programs written in many languages. C++ has neither of +these flaws, but the same low-level machine-oriented character +that makes it efficient also makes C++ less than ideal as an +algorithmic notation usable by nonexperts. + +Idol owes most of its desirable traits to its foundation, the Icon +programming language, developed at the University of Arizona +[Gris90]. In fact, Idol presents objects simply as a tool +to aid in the writing of Icon programs. Idol integrates a concise, +robust notation for object-oriented programming into a language +considerably more advanced than C or Pascal. Icon already uses a +powerful notation for expressing a general class of algorithms. The +purpose of Idol is to enhance that notation, not to get in the way. + + + Key Concepts + +This section describes the general concepts that Idol supplies +to authors of large Icon programs. The following section provides +programming examples that employ these tools. The reader is +encouraged to refer back to this section when clarification in +the examples section is needed. + +The single overriding reason for object-oriented programming +is the large program. Simple programs can be easily written in +any notation. Somewhere between the 1,000-line mark and the +10,000-line mark most programmers can no longer keep track of their +entire program at once. By using a very high-level programming language, +less lines of code are required; a programmer can write perhaps ten +times as large a program and still be able to keep track of things. +As programmers are required to write larger and larger programs, +the benefit provided by very-high level languages does not keep up +with program complexity. This obstacle has been labelled the +"software crisis", and object-oriented programming addresses this +crisis. In short, the goals of object-oriented programming are to +reduce the amount of coding required to write very large programs and +to allow code to be understood independently of the context of the +surrounding program. The techniques employed to achieve these goals +are discussed below. + + + Encapsulation + +The primary concept advocated by object-oriented programming is the +principle of encapsulation. Encapsulation is the isolation, in the +source code that a programmer writes, of a data representation and the code +that manipulates the data representation. In some sense, encapsulation +is an assertion that no other routines in the program have "side-effects" +with respect to the data structure in question. It is easier to reason +about encapsulated data because all of the source code that could affect +that data is immediately present with its definition. + +Encapsulation does for data structures what the procedure does for +algorithms: it draws a line of demarcation in the program text, the +outside of which is (or can be, or ought to be) irrelevant to the inside. +We call an encapsulated data structure an object. Just as a set of +named variables called parameters comprise the only interface between a +procedure and the code that uses it, a set of named procedures called +methods comprise the only interface between an object and the code that +uses it. + +This textual definition of encapsulation as a property of program +source code accounts for the fact that good programmers can write +encapsulated data structures in any language. The problem is not +capability, but verification. In order to verify encapsulation some +object-oriented languages, like C++, define an elaborate mechanism by +which a programmer can govern the visibility of each data structure. +Like Smalltalk, Idol instead attempts to simplify verification by +preventing violations of encapsulation entirely. + + + Inheritance + +In large programs, the same or nearly the same data structures are +used over and over again for a myriad of different purposes. Similarly, +variations on the same algorithms are employed by structure after +structure. In order to minimize redundancy, techniques are needed to +support code sharing for both data structures and algorithms. +Code is shared by related data structures by a programming concept +called inheritance. + +The basic premise of inheritance is simple: if I need to write code +for a new data structure which is similar to one that's already +written, I can specify the new structure by giving the differences +between it and the old structure, instead of copying and then modifying +the old structure's code. Obviously there are times when the +inheritance mechanism is not useful: if the two data structures are +more different than they are similar, or if they are simple enough +that inheritance would only confuse things, for example. + +Inheritance addresses a variety of common programming problems found +at different conceptual levels. The most obvious software engineering +problem it solves might be termed enhancement. During the +development of a program, its data structures may require extension +via new state variables or new operations or both; inheritance is +especially useful when both the original structure and the extension +are used by the application. Inheritance also supports +simplification, or the reduction of a data structure's state variables +or operations. Simplification is analogous to argument culling after +the fashion of the lambda calculus; it captures a logical relation +between structures rather than a common situation in software +development. In general, inheritance may be used in source code to +describe any sort of relational hyponymy, or special-casing; in Idol +the collection of all inheritance relations defines a directed (not +necessarily acyclic) graph. + + + Polymorphism + +From the perspective of the writer of related data structures, +inheritance provides a convenient method for code sharing, but +what about the code that uses objects? Since objects are +encapsulated, that code is not dependent upon the internals of +the object at all, and it makes no difference to the client code +whether the object in questions belongs to the original class or the +inheriting class. + +In fact, we can make a stronger statement. Due to encapsulation, +two different executions of some code that uses objects to implement +a particular algorithm may operate on different objects that are +not related by inheritance at all. Such code may effectively +be shared by any objects that happen to implement the operations +that the code invokes. This facility is called polymorphism, and +such algorithms are called generic. This feature is found in +non-object oriented languages; in object-oriented languages it is +a natural extension of encapsulation. + + + Object Programming + +The concepts introduced above are used in many programming languages +in one form or another. The following text presents these concepts +in the context of actual Idol code. This serves a dual purpose: +it should clarify the object model adopted by Idol as well as +provide an initial impression of these concepts' utility in coding. +In order to motivate the constructs provided by Idol, our example +begins by contrasting conventional Icon code with Idol code which +implements the same behavior. The semantics of the Idol code given +here is defined by the Idol reference manual, included later in this +document in the section entitled, "An Icon-Derived Object Language". + + Before Objects + +In order to place Idol objects in their proper context, the first +example is taken from from regular Icon. Suppose I am writing some +text-processing application such as a text editor. Such applications +need to be able to process Icon structures holding the contents of +various text files. I might begin with a simple structure like the +following: + +record buffer(filename,text,index) + +where filename is a string, text is a list of strings +corresponding to lines in the file, and index is a marker for +the current line at which the buffer is being processed. Icon record +declarations are global; in principle, if the above declaration needs +to be changed, the entire program must be rechecked. A devotee of +structured programming would no doubt write Icon procedures to read +the buffer in from a file, write it out to a file, examine, insert +and delete individual lines, etc. These procedures, along with the +record declaration given above, can be kept in a separate source file +(buffer.icn) and understood independently of the program(s) in +which they are used. Here is one such procedure: + + +# read a buffer in from a file +procedure read_buffer(b) + f := open(b.filename) | fail + b.text := [ ] + b.position := 1 + every put(b.text,!f) + close(f) + return b +end + + +There is nothing wrong with this example; in fact its similarity to the +object-oriented example that follows demonstrates that a good, modular +design is the primary effect encouraged by object-oriented programming. +Using a separate source file to contain a record type and those +procedures which operate on that type allows an Icon programmer to +maintain a voluntary encapsulation of that type. + + After Objects + +Here is the same buffer abstraction coded in Idol. This example +lays the groundwork for some more substantial techniques to follow. + +class buffer(public filename,text,index) + # read a buffer in from a file + method read() + f := open(self.filename) | fail + selferase() + every put(self.text,!f) + close(f) + return + end + # write a buffer out to a file + method write() + f := open(self.filename,"w") | fail + every write(f,!self.text) + close(f) + end + # insert a line at the current index + method insert(s) + if self.index = 1 then { + push(self.text,s) + } else if self.index > *self.text then { + put(self.text,s) + } else { + self.text := self.text[1:self.index] ||| [s] ||| + self.text[self.index:0] + } + self.index +:= 1 + return + end + # delete a line at the current index + method delete() + if self.index > *self.text then fail + rv := self.text[self.index] + if self.index=1 then pull(self.text) + else if self.index = *self.text then pop(self.text) + else self.text := self.text[1:self.index]|||self.text[self.index+1:0] + return rv + end + # move the current index to an arbitrary line + method goto(l) + if (0 <= l) & (l <= self.index+1) then return self.index := l + end + # return the current line and advance the current index + method forward() + if self.index > *self.text then fail + rv := self.text[self.index] + self.index +:= 1 + return rv + end + method erase() + self.text := [ ] + self.index := 1 + end +initially + if (self.filename) then { + if not selfread() then selferase() + } else { + self.filename := "*scratch*" + selferase() + } +end + + +This first example is not complex enough to illustrate the full +object-oriented style, but its a start. Pertaining to the +general concepts introduced above, we can make the following +initial observations: + +Polymorphism. A separate name space for each class's methods +makes for shorter names. The same method name can be used in each +class that implements a given operation. This notation is more +concise than is possible with standard Icon procedures. More +importantly it allows algorithms to operate correctly upon objects of +any class which implements the operations required by the algorithm. +Constructors. A section of code is executed automatically when +the constructor is called, allowing initialization of fields to values +other than &null. Of course, this could be simulated in Icon +by writing a procedure that had the same effect; the value of the +constructor is that it is automatic; the programmer is freed from the +responsibility of remembering to call this code everywhere objects are +created in the client program(s). This tighter coupling of memory +allocation and its corresponding initialization removes one more +source of program errors, especially on multiprogrammer projects. + + +These two observations share a common theme: the net effect is that +each piece of data is made responsible for its own behavior in the +system. Although this first example dealt with simple line-oriented +text files, the same methodology applies to more abstract entities +such as the components of a compiler's grammar (This example +is taken from the Idol translator itself, which provides another +extended example of polymorphism and inheritance.). + +Idol's code sharing facilities are illustrated if we extend the above +example. Suppose the application is more than just a text editor--- +it includes word-associative databases such as a dictionary, +bibliography, spell-checker, thesaurus, etc. These various databases +can be represented internally using Icon tables. The table entries +for the databases vary, but the databases all use string keyword +lookup. As external data, the databases can be stored in text files, +one entry per line, with the keyword at the beginning. The format +of the rest of the line varies from database to database. + +Although all these types of data are different, the code used to +read the data files can be shared, as well as the initial construction +of the tables. In fact, since we are storing our data one entry per +line in text files, we can use the code already written for buffers +to do the file i/o itself. + + +class buftable : buffer() + method read() + selfbuffer.read() + tmp := table() + every line := !self.text do + line ? { tmp[tab(many(&letters))] := line | fail } + self.text := tmp + return + end + method index(s) + return self.text[s] + end +end + + + +This concise example shows how little must be written to achieve +data structures with vastly different behavioral characteristics, +by building on code that is already written. The superclass +read() operation is one important step of the subclass +read() operation; this technique is common enough to have a +name: it is called method combination in the literature. It +allows one to view the subclass as a transformation of the +superclass. The buftable class is given in its entirety, but +our code sharing example is not complete: what about the data +structures required to support the databases themselves? They are all +variants of the buftable class, and a set of possible +implementations is given below. Note that the formats presented are +designed to illustrate code sharing; clearly, an actual application +might make different choices. + + Bibliographies + +Bibliographies might consist of a keyword followed by an uninterpreted +string of information. This imposes no additional structure on the +data beyond that imposed by the buftable class. An example +keyword would be Jeffery90. + + +class bibliography : buftable() +end + + + + + Spell-checkers + +The database for a spell-checker is presumably just a list of words, +one per line; the minimal structure required by the buftable +class given above. Some classes exist to introduce new terminology +rather than define a new data structure. In this case we introduce +a lookup operation which may fail, for use in tests. In addition, +since many spell-checking systems allow user definable dictionaries +in addition to their central database, we allow spellChecker +objects to chain together for the purpose of looking up words. + + +class spellChecker : buftable(parentSpellChecker) + method spell(s) + return (self.text[s]) | ( (self.parentSpellChecker))spell(s) + end +end + + + + + Dictionaries + +Dictionaries are slightly more involved. Each entry might consist of a +part of speech, an etymology, and an arbitrary string of uninterpreted +text comprising a definition for that entry, separated by semicolons. +Since each such entry is itself a structure, a sensible decomposition +of the dictionary structure consists of two classes: one that manages +the table and external file i/o, and one that handles the manipulation +of dictionary entries, including their decoding and encoding as +strings. + + +class dictionaryentry(word,pos,etymology,definition) + method decode(s) # decode a dictionary entry into its components + s ? { + self.word := tab(upto(';')) + move(1) + self.pos := tab(upto(';')) + move(1) + self.etymology := tab(upto(';')) + move(1) + self.definition := tab(0) + } + end + method encode() # encode a dictionary entry into a string + return self.word || ";" || self.pos || ";" || + self.etymology || ";" || self.definition + end +initially + if /self.pos then { + # constructor was called with a single string argument + selfdecode(self.word) + } +end + +class dictionary : buftable() + method read() + selfbuffer.read() + tmp := table() + every line := !self.text do + line ? { tmp[tab(many(&letters))] := dictionaryentry(line) | fail } + self.text := tmp + end + method write() + f := open(b.filename,"w") | fail + every write(f,(!self.text)encode()) + close(f) + end +end + + + + Thesauri + +Although an oversimplification, one might conceive of a thesauri as a +list of entries, each of which consists of a comma-separated list of +synonyms followed by a comma-separated list of antonyms, with a +semicolon separating the two lists. Since the code for such a +structure is nearly identical to that given for dictionaries above, +we omit it here (but one might reasonably capture a generalization +regarding entries organized as fields separated by semicolons). + + + Objects and Icon Programming Techniques + +In examining any addition to a language as large as Icon, a +significant question is how that addition relates to the rest of the +language. In particular, how does object-oriented programming fit into +the suite of advanced techniques used regularly by Icon programmers? +Previous sections of this document expound objects as an +organizational tool, analogous but more effective than the use of +separate compilation to achieve program modularity. Object-oriented +programming goes considerably beyond that viewpoint. + +Whether viewed dynamically or statically, the primary effect achieved +by object-oriented programming is the subdivision of program data in +parallel with the code. Icon already provides a variety of tools that +achieve related effects: + +Local and Static Variables in Icon procedures are the simplest +imaginable parallel association of data and code. We do not discuss +them further, although they are by no means insignificant. +Records allow a simple form of user-defined types. They provide +a useful abstraction, but keeping records associated with the right +pieces of code is still the job of the programmer. +String Scanning creates scanning environments. These are very +useful, but not very general: not all problems can be cast as +string operations. +Co-expressions save a program state for later evaluation. This +powerful facility has a sweeping range of uses, but unfortunately it +is a relatively expensive mechanism that is frequently misused to +achieve a simple effect. + + +Objects and classes, if they are successful, allow a significant +generalization of the techniques developed around the above +language mechanisms. Objects do not replace these language +mechanisms, but in many cases presented below they provide an +attractive alternative means of achieving similar effects. + + Objects and Records + +Objects are simply records whose field accesses are voluntarily +limited to a certain set of procedures. + + Objects and Scanning Environments + +String scanning in Icon is another example of associating a piece of +data with the code that operates on it. In an Icon scanning +expression of the form e1 ? e2, the result of evaluating +e1 is used implicitly in e2 via a variety of scanning +functions. In effect, the scanning operation defines a scope in which +state variables &subject and &pos are redefined. +[Walk86] proposes an extension to Icon allowing +programmer-defined scanning environments. The extension involves a new +record data type augmented by sections of code to be executed upon +entry, resumption, and exit of the scanning environment. The Icon +scanning operator was modified to take advantage of the new facility +when its first argument was of the new environment data type. + +While objects cannot emulate Icon string scanning syntactically, they +generalize the concept of the programmer-defined scanning environment. +Classes in the Idol standard library include a wide variety of +scanning environments in addition to conventional strings. The +variation is not limited to the type of data scanned; it also includes +the form and function of the scanning operations. The form of +scanning operations available are defined by the state variables they +access; in the case of Icon's built-in string scanning, a single +string and a single integer index into that string. + +There is no reason that a scanning environment cannot maintain a more +complex state, such as an input string, an output string, and a pair +of indices and directions for each string. Rather than illustrate +the use of objects to construct scanning environments with such an +abstract model, a concrete example is presented below. + + List Scanning + +List scanning is a straightforward adaptation of string scanning to +the list data type. It consists of a library class named +ListScan that implements the basic scanning operations, and +various user classes that include the scanning expressions. This +format is required due to Idol's inability to redefine the semantics +of the ? operator or to emulate its syntax in any reasonable +way. The state maintained during a list scan consists of +Subject and Pos, analogous to &subject and +&pos, respectively. + +ListScan defines analogies to the basic scanning functions of +Icon, e.g. tab, upto, many, any, etc. These +functions are used in methods of a ListScan client class, which +in turn defines itself as a subclass of ListScan. A client such as: + +class PreNum : ListScan() + method scan() + mypos := self.Pos + suspend selftab(selfupto(numeric)) + self.Pos := mypos + end +end + + +may be used in an expression such as + +(PreNum(["Tucson", "Pima", 15.0, [ ], "3"]))scan() + +producing the result ["Tucson", "Pima"]. The conventional Icon +string scanning analogy would be: "abc123" ? tab(upto(&digits)), +which produces the result "abc". Note that ListScan +methods frequently take list-element predicates as arguments where +their string scanning counterparts take csets. In the above example, +the predicate numeric supplied to upto is an Icon +function, but predicates may also be arbitrary user-defined procedures. + +The part of the Idol library ListScan class required to +understand the previous example is presented below. This code is +representative of user-defined scanning classes allowing pattern +matching over arbitrary data structures in Idol. Although +user-defined scanning is more general than Icon's built-in scanning +facilities, the scanning methods given below are always +activated in the context of a specific environment. Icon string +scanning functions can be supplied an explicit environment using +additional arguments to the function. + + +class ListScan(Subject,Pos) + method tab(i) + if i<0 then i := *self.Subject+1-i + if i<0 | i>*self.Subject+1 then fail + origPos := self.Pos + self.Pos := i + suspend self.Subject[origPos:i] + self.Pos := origPos + end + method upto(predicate) + origPos := self.Pos + every i := self.Pos to *(self.Subject) do { + if predicate(self.Subject[i]) then suspend i + } + self.Pos := origPos + end +initially + /(self.Subject) := [ ] + /(self.Pos) := 1 +end + + + + + Objects and Co-expressions + +Objects cannot come close to providing the power of co-expressions, +but they do provide a more efficient means of achieving well-known +computations such as parallel expression evaluation that have been +promoted as uses for co-expressions. In particular, a co-expression +is able to capture implicitly the state of a generator for later +evaluation; the programmer is saved the trouble of explicitly coding +what can be internally and automatically performed by Icon's +expression mechanism. While objects cannot capture a generator state +implicitly, the use of library objects mitigates the cost of +explicitly encoding the computation to be performed, as an +alternative to the use of co-expressions. The use of objects also is +a significant alternative for implementations of Icon in which +co-expressions are not available or memory is limited. + + Parallel Evaluation + +In [Gris87], co-expressions are used to obtain the results +from several generators in parallel: + +decimal := create(0 to 255) +hex := create(!"0123456789ABCDEF" || !"0123456789ABCDEF") +octal := create((0 to 3) || (0 to 7) || (0 to 7)) +character := create(image(!&cset)) +while write(right(@decimal,3)," ",@hex," ",@octal," ",@character) + + + +For the Idol programmer, one alternative to using co-expressions would +be to link in the following code from the Idol standard library: + +procedure sequence(bounds[ ]) + return Sequence(bounds) +end + +class Sequence(bounds,indices) + method max(i) + elem := self.bounds[i] + return (type(elem)== "integer",elem) | *elem-1 + end + method elem(i) + elem := self.bounds[i] + return (type(elem)== "integer",self.indices[i]) | + elem[self.indices[i]+1] + end + method activate() + top := *(self.indices) + if self.indices[1] > selfmax(1) then fail + s := "" + every i := 1 to top do { + s ||:= selfelem(i) + } + repeat { + self.indices[top] +:= 1 + if top=1 | (self.indices[top] <= selfmax(top)) then break + self.indices[top] := 0 + top -:= 1 + } + return s + end +initially + / (self.indices) := list(*self.bounds,0) +end + + + +On the one hand, the above library code is neither terse nor general +compared with co-expressions. This class does, however, allow the +parallel evaluation problem described previously to be coded as: + +dec := sequence(255) +hex := sequence("0123456789ABCDEF","0123456789ABCDEF") +octal := sequence(3,7,7) +character := sequence(string(&cset)) +while write(right(@dec,3)," ",@hex," ",@octal," ",image(@character)) + + + +$@ is the unary Idol meta-operator that invokes the +activate() operation. Since the sequence class is already +written and available, its use is an attractive alternative to +co-expressions in many settings. For example, a general class of +label generators (another use of co-expressions cited in +[Gris87]) is defined by the following library class: + +class labelgen : Sequence(prefix,postfix) + method activate() + return self.prefix||selfSequence.activate()||self.postfix + end +initially + /(self.prefix) := "" + /(self.postfix) := "" + /(self.bounds) := [50000] +end + + +After creation of a label generator object (e.g. +label := labelgen("L",":")), each resulting label is obtained +via $@label. The sequence defined by this example is + + L0: + L1: + ... + L50000: + + + + Conclusion + +Idol presents object programming as a collection of tools to reduce +the complexity of large Icon programs. These tools are encapsulation, +inheritance, and polymorphism. Since a primary goal of Idol is to +promote code sharing and reuse, a variety of specific programming +problems have elegant solutions available in the Idol class library. + + + An Icon-Derived Object Language + +This section serves as the language reference manual for Idol. Idol +is a preprocessor for Icon which implements a means of associating a +piece of data with the procedures which manipulate it. The primary +benefits to the programmer are thus organizational. The Icon +programmer may view Idol as providing an augmented record type in +which field accesses are made not directly on the records' fields, but +rather through a set of procedures associated with the type. + + + Classes + +Since Idol implements ideas found commonly in object-oriented +programming languages, its terminology is taken from that domain. The +augmented record type is called a "class". The syntax of a class is: + + +class foo(field1,field2,field3,...) + # procedures to access + # class foo objects + +[code to initialize class foo objects] +end + + + +In order to emphasize the difference between ordinary Icon procedures +and the procedures which manipulate class objects, these procedures +are called "methods" (the term is again borrowed from the +object-oriented community). Nevertheless, the syntax of a method is +that of a procedure: + + +method bar(param1,param2,param3,...) + + # Icon code which may access + # fields of a class foo object +end + + + +Since execution of a class method is always associated with a given +object of that class, the method has access to an implicit variable +called self which is a record containing fields whose names are +those given in the class declaration. References to the self variable +look just like normal record references; they use the dot (.) +operator. In addition to methods, classes may also contain regular +Icon procedure, global, and record declarations; such declarations +have the standard semantics and exist in the global Icon name space. + + + Objects + +Like records, instances of a class type are created with a constructor +function whose name is that of the class. Instances of a class are +called objects, and their fields may be initialized explicitly in the +constructor in exactly the same way as for records. For example, +after defining a class foo(x,y) one may write: + + +procedure main() + + f := foo(1,2) +end + + + +The fields of an object need not be initialized by the class +constructor. For many objects it is more logical to initialize their +fields to some standard value. In this case, the class declaration +may include an "initially" section after its methods are defined and +before its end. + +This section begins with a line containing the word "initially" and +then contains lines which are executed whenever an object of that +class is constructed. These lines may reference and assign to the +class fields as if they were normal record fields for the object being +constructed. The "record" being constructed is named self; +more on self later. + +For example, suppose one wished to implement an enhanced table type +which permitted sequential access to elements in the order they were +inserted into the table. This can be implemented by a combination of +a list and a table, both of which would initialized to the appropriate +empty structure: + + +class taque(l,t) # pronouned `taco' + + # methods to manipulate taques, + # e.g. insert, index, foreach... + +initially + self.l := [ ] + self.t := table() +end + + + +And in such a case one can create objects without including arguments +to the class constructor: + + +procedure main() + + mytaque := taque() +end + + + +In the absence of an initially section, missing arguments to a +constructor default to the null value. Together with an initially +section, the class declaration looks rather like a procedure that +constructs objects of that class. Note that one may write classes +with some fields that are initialized explicitly by the constructor +and other fields are initialized automatically in the initially +section. In this case one must either declare the automatically +initialized fields after those that are initialized in the +constructor, or insert &null in the positions of the +automatically initialized fields in the constructor. + + + + Object Invocation + +Once one has created an object with a class constructor, one +manipulates the object by invoking methods defined by its class. +Since objects are both procedures and data, object invocation is +similar to both a procedure call and a record access. The dollar +($) operator invokes one of an object's methods. The syntax is +object $ method name ( arguments ) + where the parenthesis may be omitted if the argument list +is empty. $ is used similarly to the dot (.) operator used to +access record fields. Using the taque example: + + +procedure main() + mytaque := taque() + mytaqueinsert("greetings","hello") + mytaqueinsert(123) + every write(mytaqueforeach()) + if \(mytaqueindex("hello")) + then write(", world") +end + + + +Note that direct access to an object's fields using the usual dot (.) +operator is not possible outside of a method of the appropriate class. +Attempts to reference mystack.l in procedure main() would result in +a runtime error (invalid field name). Within a class method, the +implicit variable self allows access to the object's fields in +the usual manner. The taque insert method is thus: + + + method insert(x,key) + /key := x + put(self.l,x) + self.t[key] := x + end + + + +The self variable is both a record and an object. It allows field +access just like a record, as well as method invocation like any other +object. Thus class methods can use self to invoke other class methods +without any special syntax. + + + + Inheritance + +In many cases, two classes of objects are very similar. In +particular, many classes can be thought of simply as enhancements of +some class that has already been defined. Enhancements might take the +form of added fields, added methods, or both. In other cases a class +is just a special case of another class. For example, if one had +defined a class fraction(numerator, denominator), one might want to +define a class inverses(denominator) whose behavior was identical to +that of a fraction, but whose numerator was always 1. + +Idol supports both of these ideas with the concept of inheritance. +When the definition of a class is best expressed in terms of the +definition of another class or classes, we call that class a subclass +of the other classes. This corresponds to the logical relation of +hyponymy. It means an object of the subclass can be manipulated just +as if it were an object of one of its defining classes. In practical +terms it means that similar objects can share the code that +manipulates their fields. The syntax of a subclass is + + +class foo : superclasses (fields...) + +# methods +[optional initially section] +end + + + + + Multiple Inheritance + +There are times when a new class might best be described as a +combination of two or more classes. Idol classes may have more than +one superclass, separated by colons in the class declaration. This is +called multiple inheritance. + +Subclasses define a record type consisting of all the fieldnames found +in the class itself and in all its superclasses. The subclass has +associated methods consisting of those in its own body, those in the +first superclass which were not defined in the subclass, those in the +second superclass not defined in the subclass or the first superclass, +and so on. Fields are initialized either by the constructor or by the +initially section of the first class of the class:superclass list in +which the field is defined. For example, to define a class of +inverses in terms of a class fraction(numerator,denominator) one +would write: + + +class inverse : fraction (denominator) +initially + self.numerator := 1 +end + + + +Objects of class inverse can be manipulated using all the methods +defined in class fraction; the code is actually shared by both classes +at runtime. + +Viewing inheritance as the addition of fieldnames and methods of +superclasses not already defined in the subclass is the opposite of +the more traditional object-oriented view that a subclass starts with +an instance of the superclass and augments or overrides portions of +the definition with code in the subclass body. Idol's viewpoint adds +quite a bit of leverage, such as the ability to define classes which +are subclasses of each other. This feature is described further below. + + + Invoking Superclass Operations + +When a subclass defines a method of the same name as a method defined +in the superclass, invocations on subclass objects always result in +the subclass' version of the method. This can be overridden by +explicitly including the superclass name in the invocation: + +objectsuperclass.method(parameters) + +This facility allows the subclass method to do any additional work +required for added fields before or after calling an appropriate +superclass method to achieve inherited behavior. The result is +frequently a chain of inherited method invocations. + + + + Public Fields + +As noted above, there is a strong correspondence between records and +classes. Both define new types that extend Icon's built-in +repertoire. For simple jobs, records are slightly faster as well as +more convenient: the user can directly read and write a record's +fields by name. + +Classes, on the other hand, promote the re-use of code and reduce the +complexity required to understand or maintain large, involved +structures. They should be used especially when manipulating +composite structures ontaining mixes of structures as elements, e.g. +lists containing tables, sets, and lists in various positions. + +Sometimes it is useful to access fields in an object +directly, as with records. An example from the Idol program itself is +the name field associated with methods and classes---it is a +string which is intended to be read outside the object. One can +always implement a method which returns (or assigns, for that matter) +a field value, but this gets tedious. Idol currently supports +read-only access to fields via the public keyword. If +public precedes a fieldname in a class declaration, Idol +automatically generates a method of the same name which dereferences +and returns the field. For example, the declaration + +class sinner(pharisee,public publican) + +generates code equivalent to the following class method in addition +to any explicitly defined methods: + + method publican() + return .(self.publican) + end + + + +This feature, despite its utility and the best of intentions, makes it +possible to subvert object encapsulation: it should not be +used with fields whose values are structures, since the structure +could then be modified from the outside. When invoked with the +-strict option, Idol generates code for public methods which +checks for a scalar type at runtime before returning the field. + + + + Superclass Cycles and Type Equivalence + +In many situations, there are several ways to represent the same +abstract type. Two-dimensional points might be represented by +Cartesian coordinates x and y, or equivalently by radial coordinates +expressed as degree d and radian r. If one were implementing classes +corresponding to these types there is no reason why one of them should +be considered a subclass of the other. The types are truly +interchangeable and equivalent. + +In Idol, expressing this equivalence is simple and direct. In defining +classes Cartesian and Radian we may declare them to be superclasses of +each other: + +class Cartesian : Radian (x,y) +# code which manipulates objects using cartesian coordinates +end + +class Radian : Cartesian (d,r) +# code which manipulates objects using radian coordinates +end + + +These superclass declarations make the two types equivalent names for +the same type of object; after inheritance, instances of both classes +will have fields x, y, d, and r, and support +the same set of operations. + +Equivalent types each have their own constructor given by their class +name; although they export the same set of operations, the actual +procedures invoked by the different instances may be different. For +example, if both classes define an implementation of a method +print, the method invoked by a given instance depends on +which constructor was used when the object was created. + +If a class inherits any methods from one of its equivalent +classes, it is responsible for initializing the state of all +the fields used by those methods in its own constructor, and +maintaining the state of the inherited fields when its methods make +state changes to its own fields. In the geometric example given +above, in order for class Radian to use any methods inherited +from class Cartesian, it must at least initialize x and +y explicity +in its constructor from calculations on its d and r parameters. +In general, this added responsibility is minimized in those classes +which treat an object's state as a value rather than a structure. + +The utility of equivalent types expressed by superclass cycles remains +to be seen. At the least, they provide a convenient way to write +several alternative constructors for the same class of objects. +Perhaps more importantly, their presence in Idol causes us to question +the almost religious dogmatism that the superclass graph must always +be acyclic. + + + + Miscellany + + Unary Meta-operators + +Idol supports some shorthand for convenient object invocation. In +particular, if a class defines methods named size, foreach, random, +or activate, these methods can be invoked by a modified version of +the usual Icon operator: + + +$*x is equivalent to xsize() +$?x is equivalent to xrandom() +$!x is equivalent to xforeach() +$@x is equivalent to xactivate() + + +Other operators may be added to this list. If x is an identifier +it may be used directly. If x is a more complex expression such as a +function call, it should be parenthesized, e.g. +$*(complex_expression()). +Parentheses are also required in the case of invoking an object +returned from an invocation, e.g. + + (classesindex("theClass"))name() + +These requirements are artifacts of the first implementation and are +subject to change. + + Nonunary Meta-operators + +In addition to the unary meta-operators described above, Idol supports +certain operators with more exotic capabilities. The expression +x $$ y(arguments) denotes a list invocation of method +y for object x and is analogous to Icon's list invocation operator +(binary !). Arguments is some list which will be +applied to the method as its actual parameter list. List invocation +is particularly useful in handling methods which take a variable +number of arguments and allows such methods to call each other. +Idol list invocation is a direct application of Icon list invocation +to object methods that could not be done otherwise without knowledge +of Idol internals. + +Another binary meta-operator is the object index operator given by +$[, as in the expression x $[ e ]. This expression +is an equivalent shorthand for x$index(e). Note that only +the left brace is preceded by a dollar sign. The expression in the +braces is in actuality simply a comma separated list of arguments +to the index method. + + + Constants + +As a convenience to the programmer, Idol supports constant +declarations for the builtin Icon types that are applicative--- +strings, integers, reals, and csets. Constant declarations are +similar to global variable declarations with a predefined value: + + const E_Tick := ".", E_Line := "_", E_Mask := '._' + +Constant declarations are defined from their point of declaration +to the end of the source file if they are defined globally, or to +the end of the class definition if they are located within a class. +Constants may not be declared within a procedure. Constants are +equivalent to the textual replacement of the name by the value. + + + Include Files + +Idol supports an \#include directive as a convenience to the programmer. +The include directive consists of a line beginning with the string +"\#include" followed by a filename that is optionally enclosed +in quotation marks. When the include directive is encountered, Idol +reads the contents of the named file as if it were part of the +current file. Include files may be nested, but not recursive. + +Since Idol and Icon do not have a compile-time type system, their need +for sharing via file inclusion is significantly less than in +conventional programming languages. Nevertheless, this is one of the +more frequently requested features missing in Icon. Include files are +primarily intended for the sharing of constants and global variable +identifiers in separately translated modules. + + + Implementation Restrictions + +The Idol preprocessor is written in Idol and does not actually parse +the language it purports to implement. In particular, the +preprocessor is line-oriented and the initially keyword, and the class +and method end keyword need to be on a line by themselves. Similarly, +both the object being invoked and its method name must be on the +same line for invocations. If an object invocation includes an +argument list, it must begin on the line of the invocation, since +Idol inserts parentheses for invocations where they are omitted. This +is comparable to Icon's semi-colon insertion; it is a convenience that +may prove dangerous to the novice. Likewise, the $[ index +operator, its arguments, and its corresponding close brace must all +be on the same line with the invoking object. + +Class and method declarations are less restricted: the field/parameter +list may be written over multiple lines if required, but the keyword is +recognized only if it begins a line (only whitespace may precede it), +and that line must include the class/method name, any superclasses, +and the left parenthesis that opens the field/parameter list. + +The Idol preprocessor reserves certain names for internal use. In +particular, __state and __methods are not legal class +field names. Similarly, the name idol_object is reserved in the +global name space, and may not be used as a global variable, procedure, +or record name. Finally, for each class foo amongst the user's +code, the names foo, foo__state, foo__methods, +foo__oprec are reserved, as are the names foo_bar +corresponding to each method bar in class foo. These +details are artifacts of the current implementation and are subject +to change. + + Caveats + +Subclass constructors can be confusing, especially when multiple +inheritance brings in various fields from different superclasses. +One significant problem for users of the subclass is that the +parameters expected in the constructor may not be obvious if they +are inherited from a superclass. On the other side of the spectrum, +superclasses which automatically initialize their fields can be +less than useful if the subclass might need to override the +default initialization value--the subclass must then explicitly +name the field in order to make its initially section have +precedence over the superclass. + +The first of the two problems given above can be solved by naming +fields explicitly in a subclass when initialization by constructor. +This achieves clarity at the expense of changing the inheritance +behavior, since the subclass no longer inherits the superclass +automatic initialization for that field if there is one. The latter +of the two problems can generally be solved by using the / operator +in automatic field initializations unless the initialization should +never be overridden. + +While it is occasionally convenient to redeclare an inherited field +in a subclass, accidentally doing so and then using that field to store an +unrelated value would be disastrous. Although Idol offers no proper +solution to this problem, the -strict option causes the generation +of warning messages for each redefined field name noting the relevant +sub- and superclasses. + + + + Running Idol + +Idol requires Version 8 of Icon. It runs best on UNIX +systems. It has been ported to most but not all the various systems +on which Icon runs. In particular, if your version of Icon does not +support the system() function, or your machine does not have +adequate memory available, Idol will not be able to invoke icont +to complete its translation and linking. Since Idol is untested on +some systems, you may have to make small changes to the source code +in order to port it to a new system. + +Since its initial inception, Idol has gone through several major +revisions. This document describes Idol Version 8. Contact the +author for current version information. + + + Getting a Copy + +Idol is in the public domain. It is available on the Icon RBBS and by +anonymous ftp from cs.arizona.edu. Idol is also distributed with +the program library for Version 8 of Icon and is available by U.S. +mail in this way. Interested parties may contact the author +(cjeffery@cs.arizona.edu): + + Clinton Jeffery + Department of Computer Science + University of Arizona + Tucson, AZ 85721 + + + Creating an Idol Executable + +Idol is typically distributed in both Idol and Icon source forms. +Creating an Idol executable requires a running version of Icon and a +copy of idolboot.icn, the Icon source for Idol. A second Icon +source file contains the operating-system dependent portion of Idol; +for example, unix.icn (see the Idol README file for the name of +your system file if you are not on a UNIX system; you may have to +write your own, but it is not difficult). Using icont, compile +idolboot.icn and unix.icn into an executable file (named +idolboot, or idolboot.icx). As a final step, rename this +executable to idol (or idol.icx). + + + Translating Idol Programs + +The syntax for invoking idol is normally + +idol file1[.iol] [files...] + +(on some systems you may have to say "iconx idol" where it +says "idol" above). The Idol translator creates a separate +Icon file for each class in the Idol source files you give it. On +most systems it calls icont automatically to create ucode for these +files. If the first file on the command line has any normal Icon code +in it (in addition to any class definitions it may contain), Idol +attempts to link it to any classes it may need and create an executable. + +The file extension defaults to .iol. Idol also accepts +extensions .icn, .u1, and .cl. The first two refer +to Icon source or already translated code for which Idol generates +link statements in the main (initial) Idol source file. Idol treats +arguments with the extension .cl as class names and generates +link statements for that class and its superclasses. Class names are +case-sensitive; Deque.cl is not the same class as deque.cl. + + References + + + +[Gris87] +Griswold, R.E. +Programming in Icon; Part I---Programming with + Co-Expressions. +Technical Report 87-6, Department of Computer Science, University of + Arizona, June 1987. + +[Gris90] +Griswold, R.E. and Griswold, M.T. +The Icon Programming Language, second edition. +Prentice-Hall, Englewood Cliffs, New Jersey, 1990. + +[Walk86] +Walker, K. +Dynamic Environments---A Generalization of Icon String + Scanning. +Technical Report 86-7, Department of Computer Science, University of + Arizona, March 1986. + + diff --git a/ipl/packs/idol/idolboot.icn b/ipl/packs/idol/idolboot.icn new file mode 100644 index 0000000..918a4db --- /dev/null +++ b/ipl/packs/idol/idolboot.icn @@ -0,0 +1,1265 @@ +global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha +global classes,comp,exec,strict,links,imports,loud,compiles,compatible,ct +procedure gencode() +#line 11 "idol.iol" + if \loud then write("Class import/export:") + + + + every cl := (__self1 := classes).__methods.foreach_t(__self1.__state) do (__self2 := cl).__methods.writespec(__self2.__state) + + + + repeat { + added := 0 + every super:= ((__self2 := ((__self1 := classes).__methods.foreach_t(__self1.__state))).__methods.foreachsuper(__self2.__state) | !imports) do{ + if /(__self1 := classes).__methods.lookup(__self1.__state,super) then { + added := 1 + fname := filename(super) + readinput(envpath(fname),2) + if /(__self1 := classes).__methods.lookup(__self1.__state,super) then halt("can't import class '",super,"'") + writesublink(fname) + } + } + if added = 0 then break + } + + + + every (__self2 := ((__self1 := classes).__methods.foreach_t(__self1.__state))).__methods.transitive_closure(__self2.__state) + + + + if \loud then write("Generating code:") + writesublink("i_object") + every s := !links do writelink(s) + write(fout) + every out := (__self1 := classes).__methods.foreach(__self1.__state) do { + name := filename((__self1 := out).__methods.name(__self1.__state)) + (__self1 := out).__methods.write(__self1.__state) + put(compiles,name) + writesublink(name) + } + if *compiles>0 then return cdicont(compiles) + else return +end +procedure readinput(name,phase,ct2) +#line 686 "idol.iol" + if \loud then write("\t",name) + fName := name + fLine := 0 + fin := sysopen(name,"r") + ct := \ct2 | constant() + while line := readln("wrap") do { + line ? { + tab(many(white)) + if ="class" then { + decl := class() + (__self1 := decl).__methods.read(__self1.__state,line,phase) + if phase=1 then { + (__self1 := decl).__methods.writemethods(__self1.__state) + (__self1 := classes).__methods.insert(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state)) + } else (__self1 := classes).__methods.insert_t(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state)) + } + else if ="procedure" then { + if comp = 0 then comp := 1 + decl := method("") + (__self1 := decl).__methods.read(__self1.__state,line,phase) + (__self1 := decl).__methods.write(__self1.__state,fout,"") + } + else if ="record" then { + if comp = 0 then comp := 1 + decl := declaration(line) + (__self1 := decl).__methods.write(__self1.__state,fout,"") + } + else if ="global" then { + if comp = 0 then comp := 1 + decl := vardecl(line) + (__self1 := decl).__methods.write(__self1.__state,fout,"") + } + else if ="const" then { + (__self1 := ct).__methods.append(__self1.__state,constdcl(line) ) + } + else if ="method" then { + halt("readinput: method outside class") + } + else if ="#include" then { + savedFName := fName + savedFLine := fLine + savedFIn := fin + tab(many(white)) + readinput(tab(if ="\"" then find("\"") else many(nonwhite)), + phase,ct) + fName := savedFName + fLine := savedFLine + fin := savedFIn + } + } + } + close(fin) +end +procedure readln(wrap) +#line 745 "idol.iol" + count := 0 + prefix := "" + while /finished do { + + if not (line := read(fin)) then fail + fLine +:= 1 + if match("#include",line) then return line + line[ 1(x<-find("#",line),notquote(line[1:x])) : 0] := "" + line := trim(line,white) + + x := 1 + while ((x := find("$",line,x)) & notquote(line[1:x])) do { + z := line[x+1:0] ||" " + case line[x+1] of { + + + + "(": line[x+:2] := "{" + ")": line[x+:2] := "}" + "<": line[x+:2] := "[" + ">": line[x+:2] := "]" + + + + "!"|"*"|"@"|"?": { + z ? { + move(1) + tab(many(white)) + if not (id := tab(many(alphadot))) then { + if not match("(") then halt("readln can't parse ",line) + if not (id := tab(&pos<bal())) then + halt("readln: cant bal ",&subject) + } + Op := case line[x+1] of { + "@": "activate" + "*": "size" + "!": "foreach" + "?": "random" + } + count +:= 1 + line[x:0] := + "(__self"||count||" := "||id||").__methods."|| + Op||"(__self"||count||".__state)"||tab(0) + } + } + + + + "[": { + z ? { + if not (middle := tab((&pos<bal(&cset,'[',']'))-1)[2:0]) then + halt("readln: can't bal([) ",&subject) + tail := tab(0)|"" + line := line[1:x]||"$index("||middle||")"||(tab(0)|"") + } + } + default: { + + + + reverse(line[1:x])||" " ? { + tab(many(white)) + if not (id := reverse(tab(many(alphadot)))) then { + if not match(")") then halt("readln: can't parse") + if not (id := reverse(tab(&pos<bal(&cset,')','(')))) + then halt("readln: can't bal ",&subject) + } + objlen := &pos-1 + } + count +:= 1 + front := "(__self"||count||" := "||id||").__methods." + back := "__self"||count||".__state" + + + + + z ? { + ="$" + tab(many(white)) + if not (methodname := tab(many(alphadot))) then + halt("readln: expected a method name after $") + tab(many(white)) + methodname ||:= "(" + if ="(" then { + tab(many(white)) + afterlp := &subject[&pos] + } + else { + afterlp := ")" + back ||:= ")" + } + methlen := &pos-1 + } + if line[x+1] == "$" then { + c := if afterlp[1] ~== ")" then "" else "[]" + methodname[-1] := "!(" + back := "["||back||"]|||" + } else { + c := if (\afterlp)[1] == ")" then "" else "," + } + line[x-objlen : (((*line>=(x+methlen+1))|0)\1)] := + front || methodname || back || c + } + } + } + if /wrap | (prefix==line=="") then finished := line + else { + prefix ||:= line || " " + prefix ? { + + + if ((*prefix = bal()) & (not find(",",prefix[-2]))) then + finished := prefix[1:-1] + } + } + } + return (__self1 := ct).__methods.expand(__self1.__state,finished) +end +record idol_object(__state,__methods) + +procedure declaration_read(self,decl) +#line 63 "idol.iol" + decl ? ( + (tab(many(white)) | "") , + + (self.tag := =("procedure"|"class"|"method"|"record")) , + (tab(many(white)) | "") , + + (self.name := tab(many(alpha))) , + + (tab(find("(")+1)), + (tab(many(white)) | "") , + ((__self1 := (self.fields := classFields())).__methods.parse(__self1.__state,tab(find(")")))) + ) | halt("declaration/read can't parse decl ",decl) + end +procedure declaration_write(self,f) +#line 81 "idol.iol" + write(f,(__self1 := self).__methods.String(__self1.__state)) + end +procedure declaration_String(self) +#line 87 "idol.iol" + return self.tag || " " || self.name || "(" || (__self1 := self.fields).__methods.String(__self1.__state) || ")" + end +record declaration__state(__state,__methods,name,fields,tag) +record declaration__methods(read,write,String,name) +global declaration__oprec +procedure declaration(name,fields,tag) +local self,clone +initial { + if /declaration__oprec then declarationinitialize() + } + self := declaration__state(&null,declaration__oprec,name,fields,tag) + self.__state := self + declarationinitially(self) + return idol_object(self,declaration__oprec) +end + +procedure declarationinitialize() + initial declaration__oprec := declaration__methods(declaration_read,declaration_write,declaration_String,declaration_name) +end +procedure declarationinitially(self) +#line 90 "idol.iol" + if \self.name then (__self1 := self).__methods.read(__self1.__state,self.name) +end +procedure declaration_name(self) + return .(self.name) +end + +procedure vardecl_write(self,f) +#line 98 "idol.iol" + write(f,self.s) + end +record vardecl__state(__state,__methods,s) +record vardecl__methods(write) +global vardecl__oprec +procedure vardecl(s) +local self,clone +initial { + if /vardecl__oprec then vardeclinitialize() + } + self := vardecl__state(&null,vardecl__oprec,s) + self.__state := self + return idol_object(self,vardecl__oprec) +end + +procedure vardeclinitialize() + initial vardecl__oprec := vardecl__methods(vardecl_write) +end +procedure constant_expand(self,s) +#line 107 "idol.iol" + i := 1 + + + + + while ((i <- find(k <- (__self1 := self).__methods.foreach(__self1.__state),s,i)) & ((i=1) | any(nonalpha,s[i-1])) & + ((*s = i+*k-1) | any(nonalpha,s[i+*k])) & + notquote(s[1:i])) do { + val := \ (self.t[k]) | stop("internal error in expand") + s[i +: *k] := val + + } + return s + end +procedure constant_foreach(self) +#line 122 "idol.iol" + suspend key(self.t) + end +procedure constant_eval(self,s) +#line 125 "idol.iol" + if s2 := \ self.t[s] then return s2 + end +procedure constant_parse(self,s) +#line 128 "idol.iol" + s ? { + k := trim(tab(find(":="))) | fail + move(2) + tab(many(white)) + val := tab(0) | fail + (*val > 0) | fail + self.t [ k ] := val + } + return + end +procedure constant_append(self,cd) +#line 139 "idol.iol" + every s := (__self1 := cd).__methods.parse(__self1.__state)do (__self2 := self).__methods.parse(__self2.__state,s) + end +record constant__state(__state,__methods,t) +record constant__methods(expand,foreach,eval,parse,append) +global constant__oprec +procedure constant(t) +local self,clone +initial { + if /constant__oprec then constantinitialize() + } + self := constant__state(&null,constant__oprec,t) + self.__state := self + constantinitially(self) + return idol_object(self,constant__oprec) +end + +procedure constantinitialize() + initial constant__oprec := constant__methods(constant_expand,constant_foreach,constant_eval,constant_parse,constant_append) +end +procedure constantinitially(self) +#line 142 "idol.iol" + self.t := table() +end +procedure constdcl_parse(self) +#line 151 "idol.iol" + self.s ? { + tab(find("const")+6) + tab(many(white)) + while s2 := trim(tab(find(","))) do { + suspend s2 + move(1) + tab(many(white)) + } + suspend trim(tab(0)) + } + end +record constdcl__state(__state,__methods,s) +record constdcl__methods(parse,write,vardecl) +global constdcl__oprec, vardecl__oprec +procedure constdcl(s) +local self,clone +initial { + if /constdcl__oprec then constdclinitialize() + if /vardecl__oprec then vardeclinitialize() + constdcl__oprec.vardecl := vardecl__oprec + } + self := constdcl__state(&null,constdcl__oprec,s) + self.__state := self + return idol_object(self,constdcl__oprec) +end + +procedure constdclinitialize() + initial constdcl__oprec := constdcl__methods(constdcl_parse,vardecl_write) +end +procedure body_read(self) +#line 170 "idol.iol" + self.fn := fName + self.ln := fLine + self.text := [] + while line := readln() do { + put(self.text, line) + line ? { + tab(many(white)) + if ="end" & &pos > *line then return + else if =("local"|"static"|"initial") & any(nonalpha) then { + self.ln +:= 1 + pull(self.text) + / (self.vars) := [] + put(self.vars, line) + } + } + } + halt("body/read: eof inside a procedure/method definition") + end +procedure body_write(self,f) +#line 189 "idol.iol" + if \self.vars then every write(f,!self.vars) + if \compatible then write(f," \\self := self.__state") + if \self.ln then + write(f,"#line ",self.ln + ((*\self.vars)|0)," \"",self.fn,"\"") + every write(f,(__self1 := self).__methods.foreach(__self1.__state)) + end +procedure body_delete(self) +#line 196 "idol.iol" + return pull(self.text) + end +procedure body_size(self) +#line 199 "idol.iol" + return (*\ (self.text)) | 0 + end +procedure body_foreach(self) +#line 202 "idol.iol" + if t := \self.text then suspend !self.text + end +record body__state(__state,__methods,fn,ln,vars,text) +record body__methods(read,write,delete,size,foreach) +global body__oprec +procedure body(fn,ln,vars,text) +local self,clone +initial { + if /body__oprec then bodyinitialize() + } + self := body__state(&null,body__oprec,fn,ln,vars,text) + self.__state := self + return idol_object(self,body__oprec) +end + +procedure bodyinitialize() + initial body__oprec := body__methods(body_read,body_write,body_delete,body_size,body_foreach) +end +procedure class_read(self,line,phase) +#line 214 "idol.iol" + (__self1 := self).__methods.declaration.read(__self1.__state,line) + self.supers := idTaque(":") + (__self1 := self.supers).__methods.parse(__self1.__state,line[find(":",line)+1:find("(",line)] | "") + self.methods:= taque() + self.text := body() + while line := readln("wrap") do { + line ? { + tab(many(white)) + if ="initially" then { + (__self1 := self.text).__methods.read(__self1.__state) + if phase=2 then return + (__self1 := self.text).__methods.delete(__self1.__state) + + return + } else if ="method" then { + decl := method(self.name) + (__self1 := decl).__methods.read(__self1.__state,line,phase) + (__self1 := self.methods).__methods.insert(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state)) + } else if ="end" then { + + return + } else if ="procedure" then { + decl := method("") + (__self1 := decl).__methods.read(__self1.__state,line,phase) + /self.glob := [] + put(self.glob,decl) + } else if ="global" then { + /self.glob := [] + put(self.glob,vardecl(line)) + } else if ="record" then { + /self.glob := [] + put(self.glob,declaration(line)) + } else if upto(nonwhite) then { + halt("class/read expected declaration on: ",line) + } + } + } + halt("class/read syntax error: eof inside a class definition") + end +procedure class_has_initially(self) +#line 258 "idol.iol" + return (__self1 := self.text).__methods.size(__self1.__state) > 0 + end +procedure class_ispublic(self,fieldname) +#line 261 "idol.iol" + if (__self1 := self.fields).__methods.ispublic(__self1.__state,fieldname) then return fieldname + end +procedure class_foreachmethod(self) +#line 264 "idol.iol" + suspend (__self1 := self.methods).__methods.foreach(__self1.__state) + end +procedure class_foreachsuper(self) +#line 267 "idol.iol" + suspend (__self1 := self.supers).__methods.foreach(__self1.__state) + end +procedure class_foreachfield(self) +#line 270 "idol.iol" + suspend (__self1 := self.fields).__methods.foreach(__self1.__state) + end +procedure class_isvarg(self,s) +#line 273 "idol.iol" + if (__self1 := self.fields).__methods.isvarg(__self1.__state,s) then return s + end +procedure class_transitive_closure(self) +#line 276 "idol.iol" + count := (__self1 := self.supers).__methods.size(__self1.__state) + while count > 0 do { + added := taque() + every sc := (__self1 := self.supers).__methods.foreach(__self1.__state) do { + if /(super := (__self1 := classes).__methods.lookup(__self1.__state,sc)) then + halt("class/transitive_closure: couldn't find superclass ",sc) + every supersuper := (__self1 := super).__methods.foreachsuper(__self1.__state) do { + if / (__self1 := self.supers).__methods.lookup(__self1.__state,supersuper) & + /(__self1 := added).__methods.lookup(__self1.__state,supersuper) then { + (__self1 := added).__methods.insert(__self1.__state,supersuper) + } + } + } + count := (__self1 := added).__methods.size(__self1.__state) + every (__self1 := self.supers).__methods.insert(__self1.__state,(__self2 := added).__methods.foreach(__self2.__state)) + } + end +procedure class_writedecl(self,f,s) +#line 298 "idol.iol" + writes(f, s," ",self.name) + if s=="class" & ( *(supers := (__self1 := self.supers).__methods.String(__self1.__state)) > 0 ) then + writes(f," : ",supers) + writes(f,"(") + rv := (__self1 := self.fields).__methods.String(__self1.__state,s) + if *rv > 0 then rv ||:= "," + if s~=="class" & *(\self.ifields)>0 then { + every l := !self.ifields do rv ||:= l.ident || "," + if /(superclass := (__self1 := classes).__methods.lookup(__self1.__state,l.class)) then + halt("class/resolve: couldn't find superclass ",sc) + if (__self1 := superclass).__methods.isvarg(__self1.__state,l.ident) then rv := rv[1:-1]||"[]," + } + writes(f,rv[1:-1]) + write(f,,")") + end +procedure class_writespec(self,f) +#line 314 "idol.iol" + f := envopen(filename(self.name),"w") + (__self1 := self).__methods.writedecl(__self1.__state,f,"class") + every (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.writedecl(__self2.__state,f,"method") + if (__self1 := self).__methods.has_initially(__self1.__state) then write(f,"initially") + write(f,"end") + close(f) + end +procedure class_writemethods(self) +#line 327 "idol.iol" + f:= envopen(filename(self.name,".icn"),"w") + every (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.write(__self2.__state,f,self.name) + + if \self.glob & *self.glob>0 then { + write(f,"#\n# globals declared within the class\n#") + every i := 1 to *self.glob do (__self1 := (self.glob[i])).__methods.write(__self1.__state,f,"") + } + close(f) + end +procedure class_write(self) +#line 341 "idol.iol" + f:= envopen(filename(self.name,".icn"),"a") + + + + if /self.ifields then (__self1 := self).__methods.resolve(__self1.__state) + + + + + writes(f,"record ",self.name,"__state(__state,__methods") + rv := "," + rv ||:= (__self1 := self.fields).__methods.idTaque.String(__self1.__state) + if rv[-1] ~== "," then rv ||:= "," + every s := (!self.ifields).ident do rv ||:= s || "," + write(f,rv[1:-1],")") + + + + + writes(f,"record ",self.name,"__methods(") + rv := "" + + every s := (((__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.name(__self2.__state)) | + (__self1 := self.fields).__methods.foreachpublic(__self1.__state) | + (!self.imethods).ident | + (__self1 := self.supers).__methods.foreach(__self1.__state)) + do rv ||:= s || "," + + if *rv>0 then rv[-1] := "" + write(f,rv,")") + + + + + + writes(f,"global ",self.name,"__oprec") + every writes(f,", ", (__self1 := self.supers).__methods.foreach(__self1.__state),"__oprec") + write(f) + + + + + + (__self1 := self).__methods.writedecl(__self1.__state,f,"procedure") + write(f,"local self,clone") + + + + + write(f,"initial {\n", + " if /",self.name,"__oprec then ",self.name,"initialize()") + if (__self1 := self.supers).__methods.size(__self1.__state) > 0 then + every (super <- (__self1 := self.supers).__methods.foreach(__self1.__state)) ~== self.name do + write(f," if /",super,"__oprec then ",super,"initialize()\n", + " ",self.name,"__oprec.",super," := ", super,"__oprec") + write(f," }") + + + + + writes(f," self := ",self.name,"__state(&null,",self.name,"__oprec") + every writes(f,",",(__self1 := self.fields).__methods.foreach(__self1.__state)) + if \self.ifields then every writes(f,",",(!self.ifields).ident) + write(f,")\n self.__state := self") + + + + + if (__self1 := self.text).__methods.size(__self1.__state) > 0 then write(f," ",self.name,"initially(self)") + + + + + if (__self1 := self.supers).__methods.size(__self1.__state) > 0 then { + every (super <- (__self1 := self.supers).__methods.foreach(__self1.__state)) ~== self.name do { + if (__self2 := ((__self1 := classes).__methods.lookup(__self1.__state,super))).__methods.has_initially(__self2.__state) then { + if /madeclone := 1 then { + write(f," clone := ",self.name,"__state()\n", + " clone.__state := clone\n", + " clone.__methods := ",self.name,"__oprec") + } + write(f," # inherited initialization from class ",super) + write(f," every i := 2 to *self do clone[i] := self[i]\n", + " ",super,"initially(clone)") + every l := !self.ifields do { + if l.class == super then + write(f," self.",l.ident," := clone.",l.ident) + } + } + } + } + + + + + + + write(f," return idol_object(self,",self.name,"__oprec)\n", + "end\n") + + + + + write(f,"procedure ",self.name,"initialize()") + writes(f," initial ",self.name,"__oprec := ",self.name,"__methods") + rv := "(" + every s := (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.name(__self2.__state) do { + if *rv>1 then rv ||:= "," + rv ||:= self.name||"_"||s + } + every me := (__self1 := self.fields).__methods.foreachpublic(__self1.__state) do { + if *rv>1 then rv ||:= "," + rv ||:= self.name||"_"||me + } + every l := !self.imethods do { + if *rv>1 then rv ||:= "," + rv ||:= l.class||"_"||l.ident + } + write(f,rv,")\n","end") + + + + if (__self1 := self).__methods.has_initially(__self1.__state) then { + write(f,"procedure ",self.name,"initially(self)") + (__self1 := self.text).__methods.write(__self1.__state,f) + write(f,"end") + } + + + + + every me := (__self1 := self.fields).__methods.foreachpublic(__self1.__state) do { + write(f,"procedure ",self.name,"_",me,"(self)") + if \strict then { + write(f," if type(self.",me,") == ", + "(\"list\"|\"table\"|\"set\"|\"record\") then\n", + " runerr(501,\"idol: scalar type expected\")") + } + write(f," return .(self.",me,")") + write(f,"end") + write(f) + } + + close(f) + + end +procedure class_resolve(self) +#line 492 "idol.iol" + + + + self.imethods := [] + self.ifields := [] + ipublics := [] + addedfields := table() + addedmethods := table() + every sc := (__self1 := self.supers).__methods.foreach(__self1.__state) do { + if /(superclass := (__self1 := classes).__methods.lookup(__self1.__state,sc)) then + halt("class/resolve: couldn't find superclass ",sc) + every superclassfield := (__self1 := superclass).__methods.foreachfield(__self1.__state) do { + if /(__self1 := self.fields).__methods.lookup(__self1.__state,superclassfield) & + /addedfields[superclassfield] then { + addedfields[superclassfield] := superclassfield + put ( self.ifields , classident(sc,superclassfield) ) + if (__self1 := superclass).__methods.ispublic(__self1.__state,superclassfield) then + put( ipublics, classident(sc,superclassfield) ) + } else if \strict then { + warn("class/resolve: '",sc,"' field '",superclassfield, + "' is redeclared in subclass ",self.name) + } + } + every superclassmethod := (__self2 := ((__self1 := superclass).__methods.foreachmethod(__self1.__state))).__methods.name(__self2.__state) do { + if /(__self1 := self.methods).__methods.lookup(__self1.__state,superclassmethod) & + /addedmethods[superclassmethod] then { + addedmethods[superclassmethod] := superclassmethod + put ( self.imethods, classident(sc,superclassmethod) ) + } + } + every public := (!ipublics) do { + if public.class == sc then + put (self.imethods, classident(sc,public.ident)) + } + } + end +# +# globals declared within the class +# +record classident(class,ident) +record class__state(__state,__methods,supers,methods,text,imethods,ifields,glob,name,fields,tag) +record class__methods(read,has_initially,ispublic,foreachmethod,foreachsuper,foreachfield,isvarg,transitive_closure,writedecl,writespec,writemethods,write,resolve,String,name,declaration) +global class__oprec, declaration__oprec +procedure class(supers,methods,text,imethods,ifields,glob,name,fields,tag) +local self,clone +initial { + if /class__oprec then classinitialize() + if /declaration__oprec then declarationinitialize() + class__oprec.declaration := declaration__oprec + } + self := class__state(&null,class__oprec,supers,methods,text,imethods,ifields,glob,name,fields,tag) + self.__state := self + clone := class__state() + clone.__state := clone + clone.__methods := class__oprec + # inherited initialization from class declaration + every i := 2 to *self do clone[i] := self[i] + declarationinitially(clone) + self.name := clone.name + self.fields := clone.fields + self.tag := clone.tag + return idol_object(self,class__oprec) +end + +procedure classinitialize() + initial class__oprec := class__methods(class_read,class_has_initially,class_ispublic,class_foreachmethod,class_foreachsuper,class_foreachfield,class_isvarg,class_transitive_closure,class_writedecl,class_writespec,class_writemethods,class_write,class_resolve,declaration_String,declaration_name) +end +procedure method_read(self,line,phase) +#line 535 "idol.iol" + (__self1 := self).__methods.declaration.read(__self1.__state,line) + self.text := body() + if phase = 1 then + (__self1 := self.text).__methods.read(__self1.__state) + end +procedure method_writedecl(self,f,s) +#line 541 "idol.iol" + decl := (__self1 := self).__methods.String(__self1.__state) + if s == "method" then decl[1:upto(white,decl)] := "method" + else { + decl[1:upto(white,decl)] := "procedure" + if *(self.class)>0 then { + decl[upto(white,decl)] ||:= self.class||"_" + i := find("(",decl) + decl[i] ||:= "self" || (((decl[i+1] ~== ")"), ",") | "") + } + } + write(f,decl) + end +procedure method_write(self,f) +#line 554 "idol.iol" + if self.name ~== "initially" then + (__self1 := self).__methods.writedecl(__self1.__state,f,"procedure") + (__self1 := self.text).__methods.write(__self1.__state,f) + self.text := &null + end +record method__state(__state,__methods,class,text,name,fields,tag) +record method__methods(read,writedecl,write,String,name,declaration) +global method__oprec, declaration__oprec +procedure method(class,text,name,fields,tag) +local self,clone +initial { + if /method__oprec then methodinitialize() + if /declaration__oprec then declarationinitialize() + method__oprec.declaration := declaration__oprec + } + self := method__state(&null,method__oprec,class,text,name,fields,tag) + self.__state := self + clone := method__state() + clone.__state := clone + clone.__methods := method__oprec + # inherited initialization from class declaration + every i := 2 to *self do clone[i] := self[i] + declarationinitially(clone) + self.name := clone.name + self.fields := clone.fields + self.tag := clone.tag + return idol_object(self,method__oprec) +end + +procedure methodinitialize() + initial method__oprec := method__methods(method_read,method_writedecl,method_write,declaration_String,declaration_name) +end +procedure Table_size(self) +#line 566 "idol.iol" + return (* \ self.t) | 0 + end +procedure Table_insert(self,x,key) +#line 569 "idol.iol" + /self.t := table() + /key := x + if / (self.t[key]) := x then return + end +procedure Table_lookup(self,key) +#line 574 "idol.iol" + if t := \self.t then return t[key] + return + end +procedure Table_foreach(self) +#line 578 "idol.iol" + if t := \self.t then every suspend !self.t + end +record Table__state(__state,__methods,t) +record Table__methods(size,insert,lookup,foreach) +global Table__oprec +procedure Table(t) +local self,clone +initial { + if /Table__oprec then Tableinitialize() + } + self := Table__state(&null,Table__oprec,t) + self.__state := self + return idol_object(self,Table__oprec) +end + +procedure Tableinitialize() + initial Table__oprec := Table__methods(Table_size,Table_insert,Table_lookup,Table_foreach) +end +procedure taque_insert(self,x,key) +#line 589 "idol.iol" + /self.l := [] + if (__self1 := self).__methods.Table.insert(__self1.__state,x,key) then put(self.l,x) + end +procedure taque_foreach(self) +#line 593 "idol.iol" + if l := \self.l then every suspend !self.l + end +procedure taque_insert_t(self,x,key) +#line 596 "idol.iol" + (__self1 := self).__methods.Table.insert(__self1.__state,x,key) + end +procedure taque_foreach_t(self) +#line 599 "idol.iol" + suspend (__self1 := self).__methods.Table.foreach(__self1.__state) + end +record taque__state(__state,__methods,l,t) +record taque__methods(insert,foreach,insert_t,foreach_t,size,lookup,Table) +global taque__oprec, Table__oprec +procedure taque(l,t) +local self,clone +initial { + if /taque__oprec then taqueinitialize() + if /Table__oprec then Tableinitialize() + taque__oprec.Table := Table__oprec + } + self := taque__state(&null,taque__oprec,l,t) + self.__state := self + return idol_object(self,taque__oprec) +end + +procedure taqueinitialize() + initial taque__oprec := taque__methods(taque_insert,taque_foreach,taque_insert_t,taque_foreach_t,Table_size,Table_lookup) +end +procedure idTaque_parse(self,s) +#line 609 "idol.iol" + s ? { + tab(many(white)) + while name := tab(find(self.punc)) do { + (__self1 := self).__methods.insert(__self1.__state,trim(name)) + move(1) + tab(many(white)) + } + if any(nonwhite) then (__self1 := self).__methods.insert(__self1.__state,trim(tab(0))) + } + return + end +procedure idTaque_String(self) +#line 621 "idol.iol" + if /self.l then return "" + out := "" + every id := !self.l do out ||:= id||self.punc + return out[1:-1] + end +record idTaque__state(__state,__methods,punc,l,t) +record idTaque__methods(parse,String,insert,foreach,insert_t,foreach_t,size,lookup,taque,Table) +global idTaque__oprec, taque__oprec, Table__oprec +procedure idTaque(punc,l,t) +local self,clone +initial { + if /idTaque__oprec then idTaqueinitialize() + if /taque__oprec then taqueinitialize() + idTaque__oprec.taque := taque__oprec + if /Table__oprec then Tableinitialize() + idTaque__oprec.Table := Table__oprec + } + self := idTaque__state(&null,idTaque__oprec,punc,l,t) + self.__state := self + return idol_object(self,idTaque__oprec) +end + +procedure idTaqueinitialize() + initial idTaque__oprec := idTaque__methods(idTaque_parse,idTaque_String,taque_insert,taque_foreach,taque_insert_t,taque_foreach_t,Table_size,Table_lookup) +end +procedure argList_insert(self,s) +#line 633 "idol.iol" + if \self.varg then halt("variable arg must be final") + if i := find("[",s) then { + if not (j := find("]",s)) then halt("variable arg expected ]") + s[i : j+1] := "" + self.varg := s := trim(s) + } + (__self1 := self).__methods.idTaque.insert(__self1.__state,s) + end +procedure argList_isvarg(self,s) +#line 642 "idol.iol" + if s == \self.varg then return s + end +procedure argList_String(self) +#line 645 "idol.iol" + return (__self1 := self).__methods.idTaque.String(__self1.__state) || ((\self.varg & "[]") | "") + end +record argList__state(__state,__methods,varg,punc,l,t) +record argList__methods(insert,isvarg,String,varg,parse,foreach,insert_t,foreach_t,size,lookup,idTaque,taque,Table) +global argList__oprec, idTaque__oprec, taque__oprec, Table__oprec +procedure argList(varg,punc,l,t) +local self,clone +initial { + if /argList__oprec then argListinitialize() + if /idTaque__oprec then idTaqueinitialize() + argList__oprec.idTaque := idTaque__oprec + if /taque__oprec then taqueinitialize() + argList__oprec.taque := taque__oprec + if /Table__oprec then Tableinitialize() + argList__oprec.Table := Table__oprec + } + self := argList__state(&null,argList__oprec,varg,punc,l,t) + self.__state := self + argListinitially(self) + return idol_object(self,argList__oprec) +end + +procedure argListinitialize() + initial argList__oprec := argList__methods(argList_insert,argList_isvarg,argList_String,argList_varg,idTaque_parse,taque_foreach,taque_insert_t,taque_foreach_t,Table_size,Table_lookup) +end +procedure argListinitially(self) +#line 648 "idol.iol" + self.punc := "," +end +procedure argList_varg(self) + return .(self.varg) +end + +procedure classFields_String(self,s) +#line 656 "idol.iol" + if *(rv := (__self1 := self).__methods.argList.String(__self1.__state)) = 0 then return "" + if /s | (s ~== "class") then return rv + if (__self1 := self).__methods.ispublic(__self1.__state,self.l[1]) then rv := "public "||rv + every field:=(__self1 := self).__methods.foreachpublic(__self1.__state) do rv[find(","||field,rv)] ||:= "public " + return rv + end +procedure classFields_foreachpublic(self) +#line 663 "idol.iol" + if \self.publics then every suspend !self.publics + end +procedure classFields_ispublic(self,s) +#line 666 "idol.iol" + if \self.publics then every suspend !self.publics == s + end +procedure classFields_insert(self,s) +#line 669 "idol.iol" + s ? { + if ="public" & tab(many(white)) then { + s := tab(0) + /self.publics := [] + put(self.publics,s) + } + } + (__self1 := self).__methods.argList.insert(__self1.__state,s) + end +record classFields__state(__state,__methods,publics,varg,punc,l,t) +record classFields__methods(String,foreachpublic,ispublic,insert,isvarg,varg,parse,foreach,insert_t,foreach_t,size,lookup,argList,idTaque,taque,Table) +global classFields__oprec, argList__oprec, idTaque__oprec, taque__oprec, Table__oprec +procedure classFields(publics,varg,punc,l,t) +local self,clone +initial { + if /classFields__oprec then classFieldsinitialize() + if /argList__oprec then argListinitialize() + classFields__oprec.argList := argList__oprec + if /idTaque__oprec then idTaqueinitialize() + classFields__oprec.idTaque := idTaque__oprec + if /taque__oprec then taqueinitialize() + classFields__oprec.taque := taque__oprec + if /Table__oprec then Tableinitialize() + classFields__oprec.Table := Table__oprec + } + self := classFields__state(&null,classFields__oprec,publics,varg,punc,l,t) + self.__state := self + classFieldsinitially(self) + clone := classFields__state() + clone.__state := clone + clone.__methods := classFields__oprec + # inherited initialization from class argList + every i := 2 to *self do clone[i] := self[i] + argListinitially(clone) + self.varg := clone.varg + return idol_object(self,classFields__oprec) +end + +procedure classFieldsinitialize() + initial classFields__oprec := classFields__methods(classFields_String,classFields_foreachpublic,classFields_ispublic,classFields_insert,argList_isvarg,argList_varg,idTaque_parse,taque_foreach,taque_insert_t,taque_foreach_t,Table_size,Table_lookup) +end +procedure classFieldsinitially(self) +#line 679 "idol.iol" + self.punc := "," +end +# +# Idol: Icon-derived object language, version 8.0 +# +# SYNOPSIS: +# +# idol -install +# idol prog[.iol] ... [-x args ] +# prog +# +# FILES: +# +# ./prog.iol : source file +# ./prog.icn : Icon code for non-classes in prog.iol +# ./idolcode.env/i_object.* : Icon code for the universal object type +# ./idolcode.env/classname.icn : Icon files are generated for each class +# ./idolcode.env/classname.u[12] : translated class files +# ./idolcode.env/classname : class specification/interface +# +# SEE ALSO: +# +# "Programming in Idol: An Object Primer" +# (U of Arizona Dept of CS Technical Report #90-10) +# serves as user's guide and reference manual for Idol +# +### Global variables +# +# FILES : fin = input (.iol) file, fout = output (.icn) file +# CSETS : alpha = identifier characters, nonalpha = everything else +# alphadot = identifiers + '.' +# white = whitespace, nonwhite = everything else +# TAQUES : classes in this module +# FLAGS : comp if we should try to make an executable from args[1] +# strict if we should generate paranoic encapsulation protection +# loud if Idol should generate extra console messages +# exec if we should run the result after translation +# LISTS : links = names of external icon code to link to +# imports = names of external classes to import +# compiles = names of classes which need to be compiled +# +global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha +global classes,comp,exec,strict,links,imports,loud,compiles,compatible,ct +global icontopt,tempenv + +# +# initialize global variables +# +procedure initialize() + loud := 1 + comp := 0 + alpha := &ucase ++ &lcase ++ '_' ++ &digits + nonalpha := &cset -- alpha + alphadot := alpha ++ '.' + white := ' \t\f' + nonwhite := &cset -- white + classes := taque() + links := [] + imports := [] + compiles := [] + sysinitialize() +end + +procedure main(args) + initialize() + if *args = 0 then write("usage: idol files...") + else { + if (!args ~== "-version") & + not tryenvopen(filename("i_object",".u1")) then { + tempenv := 0 + install(args) + } + every i := 1 to *args do { + if \exec then next # after -x, args are for execution + if args[i][1] == "-" then { + case map(args[i]) of { + "-c" : { + sysok := &null + if comp = 0 then comp := -1 # don't make exe + } + "-ic" : compatible := 1 + "-quiet" : loud := &null + "-strict" : strict := 1 + "-s" : sysok := &null + "-t" : comp := -2 # don't translate + "-version": return write("Idol version 8.0 of 10/6/90") & 0 + "-x" : exec := i + default : icontopt ||:= args[i] || " " + } + } + else { + \tempenv +:= 1 + if args[i] := fileroot(args[i],".cl") then { + push(imports,args[i]) + } + else if args[i] := fileroot(args[i],".icn") then { + push(links,args[i]) + icont(" -c "||args[i]) + } + else if args[i] := fileroot(args[i],".u1") then { + push(links,args[i]) + } + else if (args[i] := fileroot(args[i],".iol")) | + tryopen(filename(args[i],".iol"),"r") then { + /exe := i + args[i] := fileroot(args[i],".iol") + /fout := sysopen(filename(args[i],".icn"),"w") + readinput(filename(args[i],".iol"),1) + } else { + # + # look for an appropriate .icn, .u1 or class file + # + if tryopen(filename(args[i],".icn"),"r") then { + push(links,args[i]) + icont(" -c "||args[i]) + } + else if tryopen(filename(args[i],".u1")) then { + push(links,args[i]) + } + else if tryenvopen(args[i]) then { + push(imports,args[i]) + } + } + } + } + if gencode() then { + close(\fout) + if comp = 1 & (not makeexe(args,exe)) then + stop("Idol exits after errors creating executable") + } else { + close(\fout) + stop("Idol exits after errors translating") + } + } + # + # if we built an executable without separate compilation AND + # there's no IDOLENV class environment AND + # we had to install an environment then remove the environment + # + if (comp = 1) & (\tempenv < 2) & not getenv("IDOLENV") then uninstall() +end + +# +# tell whether the character following s is within a quote or not +# +procedure notquote(s) + outs := "" + # + # eliminate escaped quotes. + # this is a bug for people who write code like \"hello"... + s ? { + while outs ||:= tab(find("\\")+1) do move(1) + outs ||:= tab(0) + } + # see if every quote has a matching endquote + outs ? { + while s := tab(find("\""|"'")+1) do { + if not tab(find(s[-1])+1) then fail + } + } + return +end + +# +# A contemplated addition: shorthand $.foo for self.foo ? +# +#procedure selfdot(line) +# i := 1 +# while ((i := find("$.",line,i)) & notquote(line[1:i])) do line[i]:="self" +#end + +# +# error/warning/message handling +# +procedure halt(args[]) + errsrc() + every writes(&errout,!args) + stop() +end + +procedure warn(args[]) + errsrc() + every writes(&errout,!args) + write(&errout) +end + +procedure errsrc() + writes(&errout,"\"",\fName,"\", line ",\fLine,": Idol/") +end +# +# System-independent, but system related routines +# +procedure tryopen(file,mode) + if f := open(file,mode) then return close(f) +end +procedure tryenvopen(file,mode) + return tryopen(envpath(file),mode) +end +procedure sysopen(file,mode) + if not (f := open(file,mode)) then + halt("Couldn't open file ",file," for mode ",mode) + return f +end +procedure envopen(file,mode) + return sysopen(envpath(file),mode) +end +procedure writelink(s) + write(fout,"link \"",s,"\"") +end +procedure icont(argstr,prefix) +static s +initial { s := (getenv("ICONT")|"icont") } + return mysystem((\prefix|"") ||s||icontopt||argstr) +end diff --git a/ipl/packs/idol/idolmain.icn b/ipl/packs/idol/idolmain.icn new file mode 100644 index 0000000..ffcad95 --- /dev/null +++ b/ipl/packs/idol/idolmain.icn @@ -0,0 +1,215 @@ +# +# Idol: Icon-derived object language, version 8.0 +# +# SYNOPSIS: +# +# idol -install +# idol prog[.iol] ... [-x args ] +# prog +# +# FILES: +# +# ./prog.iol : source file +# ./prog.icn : Icon code for non-classes in prog.iol +# ./idolcode.env/i_object.* : Icon code for the universal object type +# ./idolcode.env/classname.icn : Icon files are generated for each class +# ./idolcode.env/classname.u[12] : translated class files +# ./idolcode.env/classname : class specification/interface +# +# SEE ALSO: +# +# "Programming in Idol: An Object Primer" +# (U of Arizona Dept of CS Technical Report #90-10) +# serves as user's guide and reference manual for Idol +# +### Global variables +# +# FILES : fin = input (.iol) file, fout = output (.icn) file +# CSETS : alpha = identifier characters, nonalpha = everything else +# alphadot = identifiers + '.' +# white = whitespace, nonwhite = everything else +# TAQUES : classes in this module +# FLAGS : comp if we should try to make an executable from args[1] +# strict if we should generate paranoic encapsulation protection +# loud if Idol should generate extra console messages +# exec if we should run the result after translation +# LISTS : links = names of external icon code to link to +# imports = names of external classes to import +# compiles = names of classes which need to be compiled +# +global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha +global classes,comp,exec,strict,links,imports,loud,compiles,compatible,ct +global icontopt,tempenv + +# +# initialize global variables +# +procedure initialize() + loud := 1 + comp := 0 + alpha := &ucase ++ &lcase ++ '_' ++ &digits + nonalpha := &cset -- alpha + alphadot := alpha ++ '.' + white := ' \t\f' + nonwhite := &cset -- white + classes := taque() + links := [] + imports := [] + compiles := [] + sysinitialize() +end + +procedure main(args) + initialize() + if *args = 0 then write("usage: idol files...") + else { + if (!args ~== "-version") & + not tryenvopen(filename("i_object",".u1")) then { + tempenv := 0 + install(args) + } + every i := 1 to *args do { + if \exec then next # after -x, args are for execution + if args[i][1] == "-" then { + case map(args[i]) of { + "-c" : { + sysok := &null + if comp = 0 then comp := -1 # don't make exe + } + "-ic" : compatible := 1 + "-quiet" : loud := &null + "-strict" : strict := 1 + "-s" : sysok := &null + "-t" : comp := -2 # don't translate + "-version": return write("Idol version 8.0 of 10/6/90") & 0 + "-x" : exec := i + default : icontopt ||:= args[i] || " " + } + } + else { + \tempenv +:= 1 + if args[i] := fileroot(args[i],".cl") then { + push(imports,args[i]) + } + else if args[i] := fileroot(args[i],".icn") then { + push(links,args[i]) + icont(" -c "||args[i]) + } + else if args[i] := fileroot(args[i],".u1") then { + push(links,args[i]) + } + else if (args[i] := fileroot(args[i],".iol")) | + tryopen(filename(args[i],".iol"),"r") then { + /exe := i + args[i] := fileroot(args[i],".iol") + /fout := sysopen(filename(args[i],".icn"),"w") + readinput(filename(args[i],".iol"),1) + } else { + # + # look for an appropriate .icn, .u1 or class file + # + if tryopen(filename(args[i],".icn"),"r") then { + push(links,args[i]) + icont(" -c "||args[i]) + } + else if tryopen(filename(args[i],".u1")) then { + push(links,args[i]) + } + else if tryenvopen(args[i]) then { + push(imports,args[i]) + } + } + } + } + if gencode() then { + close(\fout) + if comp = 1 & (not makeexe(args,exe)) then + stop("Idol exits after errors creating executable") + } else { + close(\fout) + stop("Idol exits after errors translating") + } + } + # + # if we built an executable without separate compilation AND + # there's no IDOLENV class environment AND + # we had to install an environment then remove the environment + # + if (comp = 1) & (\tempenv < 2) & not mygetenv("IDOLENV") then uninstall() +end + +# +# tell whether the character following s is within a quote or not +# +procedure notquote(s) + outs := "" + # + # eliminate escaped quotes. + # this is a bug for people who write code like \"hello"... + s ? { + while outs ||:= tab(find("\\")+1) do move(1) + outs ||:= tab(0) + } + # see if every quote has a matching endquote + outs ? { + while s := tab(find("\""|"'")+1) do { + if not tab(find(s[-1])+1) then fail + } + } + return +end + +# +# A contemplated addition: shorthand $.foo for self.foo ? +# +#procedure selfdot(line) +# i := 1 +# while ((i := find("$.",line,i)) & notquote(line[1:i])) do line[i]:="self" +#end + +# +# error/warning/message handling +# +procedure halt(args[]) + errsrc() + every writes(&errout,!args) + stop() +end + +procedure warn(args[]) + errsrc() + every writes(&errout,!args) + write(&errout) +end + +procedure errsrc() + writes(&errout,"\"",\fName,"\", line ",\fLine,": Idol/") +end +# +# System-independent, but system related routines +# +procedure tryopen(file,mode) + if f := open(file,mode) then return close(f) +end +procedure tryenvopen(file,mode) + return tryopen(envpath(file),mode) +end +procedure sysopen(file,mode) + if not (f := open(file,mode)) then + halt("Couldn't open file ",file," for mode ",mode) + return f +end +procedure envopen(file,mode) + return sysopen(envpath(file),mode) +end +procedure writelink(s) + write(fout,"link \"",s,"\"") +end +procedure icont(argstr,prefix) +static s +initial { s := (mygetenv("ICONT")|"icont") } + return mysystem((\prefix|"") ||s||icontopt||argstr) +end +procedure mygetenv(s) + return if &features == "environment variables" then getenv(s) +end diff --git a/ipl/packs/idol/incltest.iol b/ipl/packs/idol/incltest.iol new file mode 100644 index 0000000..4263bba --- /dev/null +++ b/ipl/packs/idol/incltest.iol @@ -0,0 +1,4 @@ +#include events.iol +procedure main() + write("E_Tick ",E_Tick) +end diff --git a/ipl/packs/idol/indextst.iol b/ipl/packs/idol/indextst.iol new file mode 100644 index 0000000..7cbea8f --- /dev/null +++ b/ipl/packs/idol/indextst.iol @@ -0,0 +1,10 @@ +class indextst() + method index(y) + write("index(",y,")") + end +end + +procedure main() + x := indextst() + x $[ "hello, world" ] +end diff --git a/ipl/packs/idol/install.bat b/ipl/packs/idol/install.bat new file mode 100644 index 0000000..6266353 --- /dev/null +++ b/ipl/packs/idol/install.bat @@ -0,0 +1,10 @@ +rem msdos Idol installation
+rem This compiles Idol in order to to test the system
+icont -Sr1000 -SF30 -Si1000 idolboot msdos
+mkdir idolcode.env
+iconx idolboot -t -install
+chdir idolcode.env
+icont -c i_object
+chdir ..
+iconx idolboot idol idolmain msdos
+idolt
diff --git a/ipl/packs/idol/inverse.iol b/ipl/packs/idol/inverse.iol new file mode 100644 index 0000000..b02aeb0 --- /dev/null +++ b/ipl/packs/idol/inverse.iol @@ -0,0 +1,12 @@ +class inverse:fraction(d) +initially + self.n := 1 +end + +procedure main() + x := inverse(2) + y := fraction(3,4) + z := x$times(y) + write("The decimal equivalent of ",z$asString(), + " is ",trim(z$asReal(),'0')) +end diff --git a/ipl/packs/idol/itags.iol b/ipl/packs/idol/itags.iol new file mode 100644 index 0000000..91ebb65 --- /dev/null +++ b/ipl/packs/idol/itags.iol @@ -0,0 +1,316 @@ +# itags - an Icon/Idol tag generator by Nick Kline +# hacks (such as this header comment) by Clint Jeffery +# last edit: 12/13/89 +# +# the output is a sorted list of lines of the form +# identifier owning_scope category_type filename lineno(:length) +# +# owning scope is the name of the class or procedure or record in which +# the tag is defined. +# category type is the kind of tag; one of: +# (global,procedure,record,class,method,param,obj_field,rec_field) +# +global ibrowseflag + +procedure main(args) +local line, lineno, fout, i, fin, notvar, objects, actual_file, outlines + +initial { + fout := open("ITAGS", "w") | stop("can't open ITAGS for writing"); + outlines := [[0,0,0,0,0,0]] + i := 1 + notid := &cset -- &ucase -- &digits -- &lcase -- '_' +} + +if(*args=0) then + stop("usage: itags file1 [file2 ...]") + +while i <= *args do { + if args[i] == "-i" then { + ibrowseflag := 1 + i +:= 1 + continue + } + fin := open(args[i],"r") | + stop("could not open file ",args[i]," exiting") + lineno := 1 + objects := program( args[i] ) + + while line := read(fin) do { + line[upto('#',line):0] := "" + line ? { + tab(many(' ')) + + if =("global") then { + if(any(notid)) then + every objects$addvar( getword(), lineno ) + } + + if =("procedure") then + if(any(notid)) then { + objects$addproc( getword(), lineno ) + objects$myline(tab(0),lineno) + } + + + if =("class") then + if any(notid) then { + objects$addclass( getword(), lineno ) + objects$myline(tab(0),lineno) + } + + + if =("method") then { + if any(notid) then { + objects$addmethod( getword(), lineno ) + objects$myline(tab(0),lineno) + } + } + + if =("local") then { + if any(notid) then + every objects$addvar( getword(), lineno ) + } + + if =("static") then { + if any(notid) then + every objects$addstat( getword(), lineno ) + } + + if =("record") then { + if any(notid) then { + objects$addrec( getword(), lineno ) + objects$myline(tab(0),lineno) + objects$endline( lineno) + } + } + if =("end") then + objects$endline(lineno) + } + lineno +:= 1 + } + objects$drawthyself(outlines) + i +:= 1 +} +# now process all the resulting lines +every i := 2 to *outlines do { + outlines[i] := ( + left(outlines[i][1],outlines[1][1]+1) || + left(outlines[i][2],outlines[1][2]+1) || + left(outlines[i][3],outlines[1][3]+1) || + left(outlines[i][4],outlines[1][4]+1) || + left(outlines[i][5],outlines[1][5]) || + (if \outlines[i][6] then ":"||outlines[i][6] else "")) +} +outlines := outlines[2:0] +outlines := sort(outlines) +every write(fout,!outlines) +end + +class functions(name, lineno,vars,lastline, parent, params,stat,paramtype) + +method drawthyself(outfile) +local k + every k := !self.vars do + emit(outfile, k[1], self.name, "local", self.parent$myfile(),k[2]) + every k := !self.params do + emit(outfile, k[1], self.name, self.paramtype, self.parent$myfile(),k[2]) + every k := !self.stat do + emit(outfile, k[1], self.name, "static", self.parent$myfile(),k[2]) +end + +method myline(line,lineno) +local word +static ids, letters +initial { + ids := &lcase ++ &ucase ++ &digits ++ '_' + letters := &ucase ++ &lcase +} + +line ? while tab(upto(letters)) do { + word := tab(many(ids)) + self.params|||:= [[word,lineno]] +} + +end + +method addstat(varname, lineno) + self.stat|||:=[[varname, lineno]] + return +end + +method addvar(varname, lineno) + self.vars|||:=[[varname, lineno]] + return +end + +method endline( lineno ) + self.lastline := lineno +end + +method resetcontext() + self.parent$resetcontext() +end + +initially + self.vars := [] + self.params := [] + self.stat := [] + self.paramtype := "param" +end # end of class functions + + +class proc : functions(name,lineno, parent,paramtype) + +method drawthyself(outfile) + emit(outfile,self.name, "*" , "procedure", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1) + self$functions.drawthyself(outfile) +end +initially + self.paramtype := "param" +end # of class proc + +class rec : functions(name, lineno, parent, line, paramtype) + +method drawthyself(outfile) + emit(outfile,self.name, "*", "record", self.parent$myfile(), + self.lineno) + self$functions.drawthyself(outfile) +end +initially + self.paramtype := "rec_field" +end # class record + + + +class program(public myfile, vars, proc, records, classes, curcontext, contextsave,globals) + +method endline( lineno ) + self.curcontext$endline( lineno ) + self.curcontext := pop(self.contextsave) +end + +method myline( line,lineno) + self.curcontext$myline( line,lineno) +end + +method drawthyself(outfile) + every k := !self.globals do + emit(outfile,k[1], "*", "global", self.myfile,k[2]) + every (!self.proc)$drawthyself(outfile) + every (!self.records)$drawthyself(outfile) + every (!self.classes)$drawthyself(outfile) +end + +method addmethod(name, lineno) + push(self.contextsave,self.curcontext) + self.curcontext := self.curcontext$addmethod(name,lineno) + return +end + +method addstat(varname, lineno) + self.curcontext$addstat(varname, lineno) +end + +method addvar(varname, lineno) + if self.curcontext === self + then self.globals|||:= [[varname,lineno]] + else self.curcontext$addvar(varname,lineno) + return +end + +method addproc(procname, lineno) + push(self.contextsave, self.curcontext) + self.curcontext := proc(procname, lineno, self) + self.proc|||:= [self.curcontext] + return +end + +method addrec(recname, lineno) + push(self.contextsave, self.curcontext) + self.curcontext := rec(recname, lineno,self) + self.records|||:=[self.curcontext] + return +end + +method addclass(classname, lineno) + push(self.contextsave, self.curcontext) + self.curcontext := class_(classname, lineno, self) + self.classes|||:=[self.curcontext] + return +end + +method resetcontext() + self.curcontext := pop(self.contextsave) +end + +initially + self.globals := [] + self.proc := [] + self.records := [] + self.classes := [] + self.curcontext := self + self.contextsave := [] +end # end of class program + + + +class class_ : functions (public name, lineno, parent, meth,paramtype) + +method myfile() + return self.parent$myfile() +end + +method addmethod(methname, lineno) + self.meth|||:= [methods(methname, lineno, self)] + return (self.meth[-1]) +end + +method drawthyself(outfile) + emit(outfile,self.name, "*" , "class", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1) + every (!self.meth)$drawthyself(outfile) + self$functions.drawthyself(outfile) +end + +initially + self.meth := [] + self.paramtype := "obj_field" +end #end of class_ + +class methods: functions(name, lineno, parent,paramtype) +method drawthyself(outfile) + emit(outfile,self.name, self.parent$name() , "method", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1) + self$functions.drawthyself(outfile) +end +initially + self.paramtype := "param" +end #end of members class + +procedure emit(outlist,ident, scope, type, filename, line, length) + outlist[1][1] := outlist[1][1] < *ident + outlist[1][2] := outlist[1][2] < *scope + outlist[1][3] := outlist[1][3] < *type + outlist[1][4] := outlist[1][4] < *filename + outlist[1][5] := outlist[1][5] < *line + outlist[1][6] := outlist[1][6] < *\length + if /ibrowseflag then + put( outlist, [ident,scope,type,filename,line,length] ) + else + put( outlist, [ident,scope,type,filename,line,length] ) +end + + +procedure getword() + local word + static ids,letts + initial { + ids := &ucase ++ &lcase ++ &digits ++ '_' + letts := &ucase ++ &lcase + } + + while tab(upto(letts)) do { + word := tab(many(ids)) + suspend word + } + +end diff --git a/ipl/packs/idol/labelgen.iol b/ipl/packs/idol/labelgen.iol new file mode 100644 index 0000000..cabef54 --- /dev/null +++ b/ipl/packs/idol/labelgen.iol @@ -0,0 +1,9 @@ +class labelgen : Sequence(prefix,postfix) + method activate() + return self.prefix||self$Sequence.activate()||self.postfix + end +initially + /(self.prefix) := "" + /(self.postfix) := "" + /(self.bounds) := [50000] +end diff --git a/ipl/packs/idol/lbltest.iol b/ipl/packs/idol/lbltest.iol new file mode 100644 index 0000000..ccfc919 --- /dev/null +++ b/ipl/packs/idol/lbltest.iol @@ -0,0 +1,4 @@ +procedure main() + label := labelgen("L",":") + every i := 1 to 10 do write($@label) +end diff --git a/ipl/packs/idol/linvktst.iol b/ipl/packs/idol/linvktst.iol new file mode 100644 index 0000000..1cc75cb --- /dev/null +++ b/ipl/packs/idol/linvktst.iol @@ -0,0 +1,25 @@ +# +# List invocation for methods. Icon uses binary ! but Idol +# uses $! for "foreach", so list invocation is specified via $$. +# + +class abang() + method a(args[]) + write("a:") + every write (image(!args)) + end +end + +class bbang : abang() + method b(args[]) + write("b:") + every write (image(!args)) + return self $$ a(["yo"]|||args) + end +end + +procedure main() + x := bbang() + x$b("yin","yang") + +end diff --git a/ipl/packs/idol/main.iol b/ipl/packs/idol/main.iol new file mode 100644 index 0000000..520cd09 --- /dev/null +++ b/ipl/packs/idol/main.iol @@ -0,0 +1,9 @@ +procedure main() + mydeque := Deque() + mydeque$push("hello") + mydeque$push("world") + write("My deque is size ",mydeque$size()) + every write("give me a ",mydeque$foreach()) + write("A random element is ",mydeque$random()) + write("getting ",mydeque$get()," popping ",mydeque$pop()) +end diff --git a/ipl/packs/idol/mpw.icn b/ipl/packs/idol/mpw.icn new file mode 100644 index 0000000..0518dec --- /dev/null +++ b/ipl/packs/idol/mpw.icn @@ -0,0 +1,83 @@ +# +# @(#)mpw.icn 1.4 5/5/90 +# OS-specific code for Macintosh MPW +# Adapted from unix.icn by Charles Lakos +# +global icontopt,env,sysok + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s ||:= \ext + return s +end +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end +procedure writesublink(s) + writelink(env||"_"||s) +end +procedure envpath(filename) + return env||"_"||filename +end +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + write("Installing idol environment with prefix ",env) + fout := envopen("i_object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + mysystem("delete "||exe||".icn") + if \exec then { + write("Executing:") + every i := exec+1 to *args do exe ||:= " "||args[i] + mysystem(exe) + } + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || envpath(ifile) + every ifile := !idolfiles do rms ||:= " " || envpath(ifile) || ".icn" + + if comp = -2 then return # -t --> don't translate at all + if icont(args,"") = \sysok + then mysystem("delete "||rms) + return +end +procedure sysinitialize() + icontopt := " -Sr500 -SF30 -Si1000 " + env:= "C" + sysok := 0 + loud := &null + write(&errout) + write(&errout, "*** Select and run the following commands ***") + write(&errout) +end + +procedure system(s) + write(&errout,s) + return sysok +end diff --git a/ipl/packs/idol/msdos.icn b/ipl/packs/idol/msdos.icn new file mode 100644 index 0000000..b0e7d04 --- /dev/null +++ b/ipl/packs/idol/msdos.icn @@ -0,0 +1,90 @@ +# +# @(#)msdos.icn 1.5 5/5/90 +# OS-specific code for MS-DOS Idol +# +# For systems which cannot run icont from within an Icon program, +# the approach is for Idol to generate a script/batch file to do this. +# +global icontopt,cd,md,env,sysok,batfile + +procedure mysystem(s) + if /batfile then batfile := open("idolt.bat","w") + if \loud then write(s) + write(batfile,s) + return sysok # system(s) # MS-DOS Icon is generally too big to use system() +end + +procedure filename(s,ext) + s[9:0] := "" + s ||:= \ext + return s +end +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end +procedure writesublink(s) + writelink(env||"\\\\"||s) +end +procedure envpath(filename) + return env||"\\"||filename +end +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + write("Installing idol environment in ",env) + if env ~== "" then mysystem(md||env) + if fout := envopen("i_object.icn","w") then { + write(fout,"record idol_object(__state,__methods)") + close(fout) + } else { + if not (fout := open("i_object.icn","w")) then stop("can't open i_object") + write(fout,"record idol_object(__state,__methods)") + close(fout) + mysystem("copy i_object.icn "||env) + mysystem("del i_object.icn") + } + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + if \exec then { + write("Executing:") + exe := "iconx "||exe + every i := exec+1 to *args do exe ||:= " "||args[i] + mysystem(exe) + } + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + if comp = -2 then return # -t --> don't call icont at all + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || ifile + every ifile := !idolfiles do rms ||:= " " || ifile || ".icn" + + mysystem("cd idolcode.env") + icont(args) + mysystem("cd ..") + return +end +procedure sysinitialize() + icontopt := " -Sr500 -SF30 -Si1000 " + cd := "cd " + md := "mkdir " + env := getenv("IDOLENV") | "idolcode.env" + sysok := 0 +end diff --git a/ipl/packs/idol/multitst.iol b/ipl/packs/idol/multitst.iol new file mode 100644 index 0000000..7bc1ff5 --- /dev/null +++ b/ipl/packs/idol/multitst.iol @@ -0,0 +1,27 @@ +class multitst( a, b, c, d, e, + f, g, h + , i, j, k) + method writemsg(x,y,z) + write(x,y,z) + end + method write( plus, + other + ,stuff) + every write(image(!self)) + write(plus,other,stuff) + end +initially + self$writemsg( + "this ", + "is ","not the") + self$writemsg + ("this is a","classical Icon-style bug","and it isn't printed") + self$writemsg("this ", + "is ","almost the") + self$writemsg() + self$write("end","of","test") +end + +procedure main() + multitst("hi","there","this",,"is",1,"test") +end diff --git a/ipl/packs/idol/mvs.icn b/ipl/packs/idol/mvs.icn new file mode 100644 index 0000000..40b22cf --- /dev/null +++ b/ipl/packs/idol/mvs.icn @@ -0,0 +1,99 @@ +# +# @(#)mvs.icn 1.3 5/5/90 +# OS-specific code for MVS Idol +# Adapted from os2.icn by Alan Beale (4/29/90) +# Modified by cjeffery (9/27/90) +# +global icontopt,cd,md,env,sysok,sysopen + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s $<9:0$> := "" + if \ext then return qualify(map(s, "_", "#"),ext) + else return map(s, "_", "#") +end +procedure writesublink(s) + writelink(qualify(map(s, "_", "#"),".u1")) +end +procedure envpath(filename) + return filename +end +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + fout := envopen("i#object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont($<"i#object"$>) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args$<i$> + if icont(exe) = \sysok then { + mysystem("delete "||qualify(exe, ".icn")) + if \exec then { + write("Executing:") + exe := "iconx "||exe + every i := exec+1 to *args do exe ||:= " "||args$<i$> + mysystem(exe) + } + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + + if comp = -2 then return # -t --> don't call icont at all + args := " -c" + every ifile := !idolfiles do args ||:= " " || ifile + mysystem("icont " || args) + return +end +# +# force .icn files to receive large line size, hoping to avoid +# output line splitting +# +procedure myopen(file, mode) + if not(f := open(file,mode,if mode ~== "r" then + "recfm=v,reclen=4000" else &null)) then + halt("Couldn't open file ", file, " for mode ", mode) + return f +end +# +# generate a file name from a root and a qualifier. This procedure +# is required in MVS due to the file.icn(member) syntax! +# +procedure qualify(root, qual) + if (i := upto('(', root)) then + return root$<1:i$> || qual || root$<i:0$> + else return root || qual +end +# +# remove a qualifier from a file name (but leave any member name +# intact). Fail if qualifier not found. +# +procedure fileroot(name, qual) + if not (i := find(qual, name)) then fail + if name$<i+*qual$> ~== "(" then fail + name$<i+:*qual$> := "" + return name +end + +procedure sysinitialize() + icontopt := " -Sr500 -SF30 -Si1000 " + sysok := 0 + sysopen := myopen +end + diff --git a/ipl/packs/idol/os2.icn b/ipl/packs/idol/os2.icn new file mode 100644 index 0000000..068da17 --- /dev/null +++ b/ipl/packs/idol/os2.icn @@ -0,0 +1,90 @@ +# +# @(#)os2.icn 1.5 5/5/90 +# OS-specific code for OS/2 Idol +# Adapted from msdos.icn by cheyenne wills +# +global icontopt,cd,md,env,sysok + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s[9:0] := "" + s ||:= \ext + return s +end +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end +procedure writesublink(s) + writelink(env||"\\\\"||s) +end +procedure envpath(filename) + return env||"\\"||filename +end +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + write("Installing idol environment in ",env) + if env ~== "" then mysystem(md||env) + fout := envopen("i_object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + mysystem((if find("UNIX",&features) then "rm " else "del ")||exe||".icn") + if \exec then { + write("Executing:") + if not find("UNIX",&features) then exe := "iconx "||exe + every i := exec+1 to *args do exe ||:= " "||args[i] + mysystem(exe) + } + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) +initial { s := (getenv("ICONT")|"icont") } + + if comp = -2 then return # -t --> don't call icont at all + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || ifile + every ifile := !idolfiles do rms ||:= " " || ifile || ".icn" + cdcmd := open("idolenv.cmd","w") + write(cdcmd,"@echo off") + write(cdcmd,"cd idolcode.env") + write(cdcmd,s,args) + write(cdcmd,"if errorlevel 1 goto xit") + every ifile := !idolfiles do + write(cdcmd,"del ",ifile,".icn") + write(cdcmd,":xit") + write(cdcmd,"cd ..") + close(cdcmd) + mysystem("idolenv.cmd") + mysystem("del idolenv.cmd") + return +end +procedure sysinitialize() + icontopt := " -Sr500 -SF30 -Si1000 " + cd := "cd " + md := "mkdir " + env := getenv("IDOLENV") | "idolcode.env" + sysok := 0 +end diff --git a/ipl/packs/idol/point.iol b/ipl/packs/idol/point.iol new file mode 100644 index 0000000..41d0d08 --- /dev/null +++ b/ipl/packs/idol/point.iol @@ -0,0 +1,14 @@ +class Cartesian : Radian (x,y) +initially + if /(self.r) then { + self.r := sqrt(self.x^2+self.y^2) + self.d := 0 # this should really be some awful mess + } +end +class Radian : Cartesian(d,r) +initially + if /(self.x) then { + self.x := 0 + self.y := 0 + } +end diff --git a/ipl/packs/idol/seqtest.iol b/ipl/packs/idol/seqtest.iol new file mode 100644 index 0000000..944b322 --- /dev/null +++ b/ipl/packs/idol/seqtest.iol @@ -0,0 +1,7 @@ +procedure main() + decimal := sequence(255) + hex := sequence("0123456789ABCDEF","0123456789ABCDEF") + octal := sequence(3,7,7) + character := sequence(string(&cset)) + while write(right($@decimal,3)," ",$@hex," ",$@octal," ",image($@character)) +end diff --git a/ipl/packs/idol/sequence.iol b/ipl/packs/idol/sequence.iol new file mode 100644 index 0000000..87bc2b7 --- /dev/null +++ b/ipl/packs/idol/sequence.iol @@ -0,0 +1,31 @@ +procedure sequence(bounds[ ]) + return Sequence(bounds) +end + +class Sequence(bounds,indices) + method max(i) + elem := self.bounds[i] + return (type(elem)== "integer",elem) | *elem-1 + end + method elem(i) + elem := self.bounds[i] + return (type(elem)== "integer",self.indices[i]) | elem[self.indices[i]+1] + end + method activate() + top := *(self.indices) + if self.indices[1] > self$max(1) then fail + s := "" + every i := 1 to top do { + s ||:= self$elem(i) + } + repeat { + self.indices[top] +:= 1 + if top=1 | (self.indices[top] <= self$max(top)) then break + self.indices[top] := 0 + top -:= 1 + } + return s + end +initially + / (self.indices) := list(*self.bounds,0) +end diff --git a/ipl/packs/idol/sinvktst.iol b/ipl/packs/idol/sinvktst.iol new file mode 100644 index 0000000..cd0f34d --- /dev/null +++ b/ipl/packs/idol/sinvktst.iol @@ -0,0 +1,13 @@ +class sinvbuffer : strinvokable() + method forward_char() + write("success") + end + method eval(s,args[]) + suspend self$strinvokable.eval(map(s,"-","_")) + end +end + +procedure main() + x := sinvbuffer() + x $ eval("forward-char") +end diff --git a/ipl/packs/idol/strinvok.iol b/ipl/packs/idol/strinvok.iol new file mode 100644 index 0000000..ba54bf9 --- /dev/null +++ b/ipl/packs/idol/strinvok.iol @@ -0,0 +1,18 @@ +# +# a builtin class, subclasses of which support string invocation for methods +# (sort of) +# this is dependent upon Idol internals which are subject to change... +# +class strinvokable() + method eval(s,args[]) + i := 1 + every methodname := name(!(self.__methods)) do { + methodname[1 : find(".",methodname)+1 ] := "" + if s == methodname then { + suspend self.__methods[i] ! ([self]|||args) + fail + } + i +:= 1 + } + end +end diff --git a/ipl/packs/idol/systems.txt b/ipl/packs/idol/systems.txt new file mode 100644 index 0000000..8dc4324 --- /dev/null +++ b/ipl/packs/idol/systems.txt @@ -0,0 +1,66 @@ +This file contains system-dependent notes on Idol. Compiling idolboot +for your system requires a command of the form + icont -Sr1000 -SF30 -Si1000 idolboot system +where system is the name of your system (so far amiga, mpw, msdos, +mvs, os2, unix, or vms). + +UNIX + +If you are running UNIX, count yourself lucky! The Idol distribution +comes with a Makefile which ought to take care of things for you. + +MSDOS + +Due to memory limitations, Idol for MS-DOS Icon does not use the system() +function. Instead, it generates a batch file, idolt.bat, containing the +sequence of commands required to finish the translation and linking of +the output into executable icode. The batch file idol.bat runs idol +and then calls idolt for you; it should suffice in ordinary situations. +It is invoked as described in the man page and reference manual, e.g. + C> idol idol msdos +The file install.bat performs the initial bootstrap translation of idol. +Note that the translation scripts cannot automatically remove .icn files, +so you may have to remove them manually if your disk space is precious. + +VMS + +Idol compiles and runs under VMS Icon version 7.0, but its a little +klunky; idol may fail to execute icont, or icont may fail to execute +ilink (under version 7.0). Unfortunately I do not have access +to a VMS machine running a current version of Icon. Note that there +are two DCL scripts in the distribution: vms.com is used by Idol +internally, while vmsidol.com is a convenience script if icont fails +on your system when invoked from inside Idol. You are encouraged to +rename vmsidol.com to idol.com; it is not named idol.com to avoid +a nasty situation for MS-DOS users where .com files are assumed to +be binary executables! Remember when specifying options to either idol +or icont one must put quotes around the argument in order for VMS to +leave it alone! + +OS/2 + +Cheyenne Wills has provided us all with an OS/2 system file! +Although problems should be reported to me, the credit is all his. + +MPW + +Charles Lakos has provided a system file for Icon running under the +Macintosh Programmer's Workshop. Icon source for class X is generated +as C_X.icn. After the Idol translation phase, the commands for the +Icon translation have been written to the MPW Worksheet. They can +simply be selected and run. Thanks Charles! + +AMIGA + +Idol runs fairly comfortably on Version 8 of Amiga Icon (it won't work +with Version 7.5 of Amiga Icon). + +MVS + +Alan Beale has ported Idol to IBM mainframes running MVS. This was a +bigger job than most ports! Thanks Alan. + +OTHERS + +Porting idol consists of writing a new system.icn file for your system. +Take a look at unix.icn, vms.icn, os2.icn, mpw.icn, and msdos.icn. diff --git a/ipl/packs/idol/unix.icn b/ipl/packs/idol/unix.icn new file mode 100644 index 0000000..3f2e4af --- /dev/null +++ b/ipl/packs/idol/unix.icn @@ -0,0 +1,80 @@ +# +# @(#)unix.icn 1.6 3/14/91 +# OS-specific code for UNIX Idol +# +global icontopt,env,sysok,comp + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s[9:0] := "" + s ||:= \ext + return s +end + +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end + +procedure writesublink(s) + writelink(env||"/"||s) +end + +procedure envpath(filename) + return env||"/"||filename +end + +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + if "-t" == !args then comp := -2 + write("Installing idol environment in ",env) + if env ~== "" then mysystem("mkdir "||env) + fout := envopen("i_object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + mysystem("rm -r "||env) +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + mysystem("rm "||exe||".icn") + if \exec then { + write("Executing:") + every i := exec+1 to *args do exe ||:= " "||args[i] + return mysystem(exe) + } else return + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + if comp = -2 then return # -t --> don't translate at all + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || ifile + every ifile := !idolfiles do rms ||:= " " || ifile || ".icn" + + if (rv := icont(args,"cd "||env||"; ")) = \sysok + then mysystem("cd "||env||"; rm "||rms) + if \rv = 0 then return rv +end +procedure sysinitialize() + icontopt := " -s " + env := getenv("IDOLENV") | "idolcode.env" + sysok := 0 +end diff --git a/ipl/packs/idol/vms.com b/ipl/packs/idol/vms.com new file mode 100644 index 0000000..e104e04 --- /dev/null +++ b/ipl/packs/idol/vms.com @@ -0,0 +1,4 @@ +$ ! A script used internally by Idol on VMS +$ set default [.idolenv] +$ icont -c 'P1' +$ set default [-] diff --git a/ipl/packs/idol/vms.icn b/ipl/packs/idol/vms.icn new file mode 100644 index 0000000..8a15e97 --- /dev/null +++ b/ipl/packs/idol/vms.icn @@ -0,0 +1,78 @@ +# +# @(#)vms.icn 1.6 5/5/90 +# OS-specific code for VMS Idol +# +global icontopt,cd,md,env,sysok + +procedure mysystem(s) + if \loud then write(s) + return system(s) +end + +procedure filename(s,ext) + s[9:0] := "" + s ||:= \ext + return s +end +# if the filename s has extension ext then return the filename less the +# extension, otherwise fail. +procedure fileroot(s,ext) + if s[- *ext : 0] == ext then return s[1 : - *ext] +end +procedure writesublink(s) + writelink(env||s) +end +procedure envpath(filename) + return env||filename +end +# +# Installation. +# Uses hierarchical filesystem on some systems (see initialize) +# +procedure install(args) + write("Installing idol environment in ",env) + if env ~== "" then mysystem(md||env) + fout := envopen("i_object.icn","w") + write(fout,"record idol_object(__state,__methods)") + close(fout) + fout := &null + cdicont(["i_object"]) +end +procedure uninstall(args) + # not implemented yet +end + +procedure makeexe(args,i) + exe := args[i] + if icont(exe) = \sysok then { + mysystem("del "||exe||".icn") + if \exec then { + write("Executing:") + exe := "iconx "||exe + every i := exec+1 to *args do exe ||:= " "||args[i] + mysystem(exe) + } + } +end +# +# system-dependent compilation of idolfile.icn +# (in the idol subdirectory, if there is one) +# +procedure cdicont(idolfiles) + if comp = -2 then return # -t --> don't icont at all + args := " -c" + rms := "" + every ifile := !idolfiles do args ||:= " " || ifile + every ifile := !idolfiles do rms ||:= " " || ifile || ".icn" + + every ifile := !idolfiles do mysystem("@vms "||ifile||".icn") + return +end + +procedure sysinitialize() + icontopt := " \"-Sr500\" \"-Si1000\" \"-SF30\" \"-Sg500\" " + cd := "set default " + md := "create/dir " + env := getenv("IDOLENV") | "[.idolenv]" + sysok := 1 +end diff --git a/ipl/packs/idol/vmsidol.com b/ipl/packs/idol/vmsidol.com new file mode 100644 index 0000000..11d8f9c --- /dev/null +++ b/ipl/packs/idol/vmsidol.com @@ -0,0 +1,3 @@ +$ ! VMS Idol invocation script for simple compiles +$ iconx idol "-t" 'P1' 'P2' 'P3' 'P4' 'P5' 'P6' 'P7' 'P8' 'P9' +$ icont "-Sr1000" "-Sg500" "-SF30" 'P1' diff --git a/ipl/packs/idol/warntest.iol b/ipl/packs/idol/warntest.iol new file mode 100644 index 0000000..f0600b9 --- /dev/null +++ b/ipl/packs/idol/warntest.iol @@ -0,0 +1,8 @@ +# This is a test of the emergency broadcasting system. +# This is only a test. + +class a ( field ) +end + +class b : a ( field ) +end |