summaryrefslogtreecommitdiff
path: root/ipl/packs/idol
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/packs/idol')
-rw-r--r--ipl/packs/idol/Makefile23
-rw-r--r--ipl/packs/idol/NEW.8_064
-rw-r--r--ipl/packs/idol/README50
-rw-r--r--ipl/packs/idol/amiga.icn85
-rw-r--r--ipl/packs/idol/autoparn.iol15
-rw-r--r--ipl/packs/idol/bi_test.iol30
-rw-r--r--ipl/packs/idol/buffer.iol132
-rw-r--r--ipl/packs/idol/buftest.iol19
-rw-r--r--ipl/packs/idol/builtins.iol170
-rw-r--r--ipl/packs/idol/consttst.iol12
-rw-r--r--ipl/packs/idol/events.iol1
-rw-r--r--ipl/packs/idol/fraction.iol19
-rw-r--r--ipl/packs/idol/globtest.iol8
-rw-r--r--ipl/packs/idol/ictest.iol11
-rw-r--r--ipl/packs/idol/idol.1134
-rw-r--r--ipl/packs/idol/idol.bat2
-rw-r--r--ipl/packs/idol/idol.hqx179
-rw-r--r--ipl/packs/idol/idol.iol863
-rw-r--r--ipl/packs/idol/idol.man58
-rw-r--r--ipl/packs/idol/idol.txt1325
-rw-r--r--ipl/packs/idol/idolboot.icn1265
-rw-r--r--ipl/packs/idol/idolmain.icn215
-rw-r--r--ipl/packs/idol/incltest.iol4
-rw-r--r--ipl/packs/idol/indextst.iol10
-rw-r--r--ipl/packs/idol/install.bat10
-rw-r--r--ipl/packs/idol/inverse.iol12
-rw-r--r--ipl/packs/idol/itags.iol316
-rw-r--r--ipl/packs/idol/labelgen.iol9
-rw-r--r--ipl/packs/idol/lbltest.iol4
-rw-r--r--ipl/packs/idol/linvktst.iol25
-rw-r--r--ipl/packs/idol/main.iol9
-rw-r--r--ipl/packs/idol/mpw.icn83
-rw-r--r--ipl/packs/idol/msdos.icn90
-rw-r--r--ipl/packs/idol/multitst.iol27
-rw-r--r--ipl/packs/idol/mvs.icn99
-rw-r--r--ipl/packs/idol/os2.icn90
-rw-r--r--ipl/packs/idol/point.iol14
-rw-r--r--ipl/packs/idol/seqtest.iol7
-rw-r--r--ipl/packs/idol/sequence.iol31
-rw-r--r--ipl/packs/idol/sinvktst.iol13
-rw-r--r--ipl/packs/idol/strinvok.iol18
-rw-r--r--ipl/packs/idol/systems.txt66
-rw-r--r--ipl/packs/idol/unix.icn80
-rw-r--r--ipl/packs/idol/vms.com4
-rw-r--r--ipl/packs/idol/vms.icn78
-rw-r--r--ipl/packs/idol/vmsidol.com3
-rw-r--r--ipl/packs/idol/warntest.iol8
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