home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ICONPL8.ZIP / IDOL.PAK < prev    next >
Text File  |  1990-03-23  |  142KB  |  4,650 lines

  1. ##########
  2. Makefile
  3. #
  4. # Sample makefile for compiling Idol
  5. #
  6. idol: idol.iol unix.u1 idolboot
  7.     idolboot idol unix.u1
  8.  
  9. idolboot: idolboot.icn unix.u1
  10.     icont -Sr1000 -SF30 -Si1000 idolboot unix.u1
  11.     idolboot -install
  12.  
  13. unix.u1: unix.icn
  14.     icont -c unix
  15. ##########
  16. README
  17. This is the Idol public distribution directory.
  18. Read idol.man and idol.doc for details on running Idol.
  19.  
  20. The Idol source is idol.iol; the Idol booting kit is idolboot.icn.
  21. In addition to these two files, there is a system-specific Icon file
  22. which must be linked in to produce an Idol executable: so far there
  23. are files amiga.icn, mpw.icn, msdos.icn, os2.icn, unix.icn, and vms.icn.
  24.  
  25. BUILDING IDOL
  26.  
  27. If you are running MS-DOS, the file install.bat contains the sequence
  28. of commands necessary to build Idol.  This sequence consists of:
  29.  
  30. (1) Compile idolboot with a line such as
  31.     icont -Sr1000 -SF30 -Si1000 idolboot msdos
  32.  
  33. (2) Install an Idol environment directory with a line such as
  34.     iconx idolboot -install
  35. For MS-DOS, this generates a batch file named idolt.bat which
  36. you would then execute to create the environment directory.
  37. For other systems, idolboot creates the directory itself.
  38.  
  39. (3) Translate Idol from its idol.iol source file with a line such as
  40.     iconx idolboot idol msdos.icn
  41. (Again, on MS-DOS, this generates a batch file named idolt.bat
  42. which you should then execute.)
  43.  
  44. This makes a good initial test of the system's operation.
  45.  
  46. In addition there are several other files with extension .iol; these
  47. are unfinished fragments of Idol source code for your perusal.
  48. Contributions are of course welcome!
  49.  
  50. Note that Idol is still a work in progress, and this must be
  51. considered a test distribution.  Support for non-UNIX systems is
  52. minimally tested; feel free to add code to support your system
  53. and send it in.
  54.  
  55. The -strict flag not only generates paranoid code for public field
  56. access, it generates extra warning messages when inherited fields
  57. are named in a subclass.
  58.  
  59. Mail cjeffery@cs.arizona.edu (or uunet!arizona!cjeffery)
  60. when you have questions or bug fixes for Idol.
  61. ##########
  62. amiga.icn
  63. #
  64. # %W% %G%
  65. # OS-specific code for Amiga Idol
  66. #
  67. global lnkopt,cd,md,env,sysok
  68.  
  69. procedure mysystem(s)
  70.   if \loud then write(s)
  71.   return system(s)
  72. end
  73.  
  74. procedure filename(s)
  75.   s[9:0] := ""
  76.   return s
  77. end
  78. procedure writesublink(s)
  79.   writelink(env||"/"||s)
  80. end
  81. procedure envpath(filename)
  82.   return env||"/"||filename
  83. end
  84. #
  85. # Installation.
  86. # Uses hierarchical filesystem on some systems (see initialize)
  87. #
  88. procedure install(args)
  89.   write("Installing idol environment in ",env)
  90.   if env ~== "" then mysystem(md||env)
  91.   fout := envopen("i_object.icn","w")
  92.   write(fout,"record idol_object(__state,__methods)")
  93.   close(fout)
  94.   fout := &null
  95.   cdicont(["i_object"])
  96. end
  97.  
  98. procedure makeexe(args,i)
  99.   exe := args[i]
  100.   if icont(lnkopt||exe) = \sysok then {
  101.       mysystem("delete "||exe||".icn")
  102.       if \exec then {
  103.     write("Executing:")
  104.     exe := "iconx "||exe
  105.     every i := exec+1 to *args do exe ||:= " "||args[i]
  106.     mysystem(exe)
  107.       }
  108.   }
  109. end
  110. #
  111. # system-dependent compilation of idolfile.icn
  112. #   (in the idol subdirectory, if there is one)
  113. #
  114. procedure cdicont(idolfiles)
  115.   if comp = -2 then return  # -t --> don't call icont at all
  116.   args := " -c"
  117.   rms  := ""
  118.   every ifile := !idolfiles do args ||:= " " || ifile
  119.   every ifile := !idolfiles do rms  ||:= " " || ifile || ".icn"
  120.  
  121.   mysystem("cd idolcode.env")
  122.   if icont(args) = \sysok
  123.   then every ifile := !idolfiles do mysystem("delete "||ifile||".icn")
  124.   mysystem("cd /")
  125. end
  126. procedure sysinitialize()
  127.   lnkopt := " -Sr500 -SF30 -Si1000 "
  128.   cd := "cd "
  129.   md := "makedir "
  130.   env := "idolcode.env"
  131.   sysok := 0
  132. end
  133. ##########
  134. bi_test.iol
  135. #
  136. # Tests for the various builtins
  137. #
  138. procedure main()
  139.  
  140.   x := Table(1)
  141.   write("\nTesting class ",x$class())
  142.   x$setElement("world","hello")
  143.   write(x$getElement("world"))
  144.   write(x$getElement("hello"))
  145.  
  146.   x := Deque()
  147.   write("\nTesting class ",x$class())
  148.   x$push("hello")
  149.   x$push("world")
  150.   write("My deque is size ",$*x)
  151.   every write("give me a ",$!x)
  152.   write("A random element is ",$?x)
  153.   write("getting ",x$get()," popping ",x$pop())
  154.  
  155.   x := List(["Tucson", "Pima", 85721])
  156.   write("\nTesting class ",x$class())
  157.   every write("give me a ",$!x)
  158.  
  159. end
  160. ##########
  161. buffer.iol
  162.     class buffer(public filename,text,index)
  163.       # read a buffer in from a file
  164.       method read()
  165.         f := open(self.filename,"r") | fail
  166.         self$erase()
  167.         every put(self.text,!f)
  168.         close(f)
  169.         return
  170.       end
  171.       # write a buffer out to a file
  172.       method write()
  173.         f := open(self.filename,"w") | fail
  174.         every write(f,!self.text)
  175.         close(f)
  176.       end
  177.       # insert a line at the current index
  178.       method insert(s)
  179.         if self.index = 1 then {
  180.           push(self.text,s)
  181.         } else if self.index > *self.text then {
  182.           put(self.text,s)
  183.         } else {
  184.           self.text := self.text[1:self.index]|||[s]|||self.text[self.index:0]
  185.         }
  186.         self.index +:= 1
  187.         return
  188.       end
  189.       # delete a line at the current index
  190.       method delete()
  191.         if self.index > *self.text then fail
  192.         rv := self.text[self.index]
  193.     if self.index=1 then pull(self.text)
  194.     else if self.index = *self.text then pop(self.text)
  195.     else self.text := self.text[1:self.index]|||self.text[self.index+1:0]
  196.         return rv
  197.       end
  198.       # move the current index to an arbitrary line
  199.       method goto(l)
  200.         if (0 <= l) & (l <= self.index+1) then return self.index := l
  201.       end
  202.       # return the current line and advance the current index
  203.       method forward()
  204.         if self.index > *self.text then fail
  205.         rv := self.text[self.index]
  206.         self.index +:= 1
  207.         return rv
  208.       end
  209.       # place the buffer's text into a contiguously allocated list
  210.       method linearize()
  211.         tmp := list(*self.text)
  212.         every i := 1 to *tmp do tmp[i] := self.text[i]
  213.         self.text := tmp
  214.       end
  215.       method erase()
  216.         self.text     := [ ]
  217.         self.index    := 1
  218.       end
  219.     initially
  220.       if \ (self.filename) then {
  221.         if not self$read() then self$erase()
  222.       } else {
  223.         self.filename := "*scratch*"
  224.         self.erase()
  225.       }
  226.     end
  227.  
  228.  
  229. class buftable : buffer()
  230.   method read()
  231.     self$buffer.read()
  232.     tmp := table()
  233.     every line := !self.text do
  234.       line ? { tmp[tab(many(&ucase++&lcase))] := line | fail }
  235.     self.text := tmp
  236.     return
  237.   end
  238.   method lookup(s)
  239.     return self.text[s]
  240.   end
  241. end
  242.  
  243.  
  244. class bibliography : buftable()
  245. end
  246.  
  247.  
  248. class spellChecker : buftable(parentSpellChecker)
  249.   method spell(s)
  250.     return \ (self.text[s]) | (\ (self.parentSpellChecker))$spell(s)
  251.   end
  252. end
  253.  
  254.  
  255. class dictentry(word,pos,etymology,definition)
  256.   method decode(s) # decode a dictionary entry into its components
  257.     s ? {
  258.       self.word       := tab(upto(';'))
  259.       move(1)
  260.       self.pos        := tab(upto(';'))
  261.       move(1)
  262.       self.etymology  := tab(upto(';'))
  263.       move(1)
  264.       self.definition := tab(0)
  265.     }
  266.   end
  267.   method encode()  # encode a dictionary entry into a string
  268.     return self.word||";"||self.pos||";"||self.etymology||";"||self.definition
  269.   end
  270. initially
  271.   if /self.pos then {
  272.     # constructor was called with a single string argument
  273.     self$decode(self.word)
  274.   }
  275. end
  276.  
  277. class dictionary : buftable()
  278.   method read()
  279.     self$buffer.read()
  280.     tmp := table()
  281.     every line := !self.text do
  282.       line ? { tmp[tab(many(&ucase++&lcase))] := dictentry(line) | fail }
  283.     self.text := tmp
  284.   end
  285.   method write()
  286.     f := open(b.filename,"w") | fail
  287.     every write(f,(!self.text)$encode())
  288.     close(f)
  289.   end
  290. end
  291. ##########
  292. buftest.iol
  293. # buffer classes' tests
  294.  
  295. procedure main(args)
  296.   if *args=0 then stop("usage: buftest cp file1 file2")
  297.   every i := 1 to *args do {
  298.       case args[i] of {
  299.       "cp": {
  300.           cp(args)
  301.       }
  302.       }
  303.   }
  304. end
  305. procedure cp(args)
  306.   b1 := buffer(args[2])
  307.   b2 := buffer(args[3])
  308.   b2$erase()
  309.   while s:=b1$forward() do b2$insert(s)
  310.   b2$write()
  311. end
  312. ##########
  313. builtins.iol
  314. # %W% %G%
  315. #
  316. # Builtin Icon objects, roughly corresponding to the language builtins.
  317. #
  318. # Taxonomy of builtin types:
  319. #
  320. #                   __Object___
  321. #                           _-'           `-_
  322. #             _-'                  `-_
  323. #          Collection            Atom_
  324. #         /    |    \                      _'     `-.
  325. #    Stack    Queue    Vector           _-'        Number
  326. #           \   /      /  |  \          _-'            /      \ 
  327. #        Deque     /      |   \          _'     Integer           Real
  328. #               \    /    |    \     /
  329. #        List    Table    String
  330. #
  331. #    
  332.  
  333. #
  334. # this is the Smalltalk-style ideal root of an inheritance hierarchy.
  335. # add your favorite methods here.
  336. #
  337. class Object()
  338.   method class()
  339.     return image(self)[8:find("_",image(self))]
  340.   end
  341. end
  342.  
  343. class Collection : Object (theCollection)
  344.   method size()
  345.     return *self.theCollection
  346.   end
  347.   method foreach()
  348.     suspend !self.theCollection
  349.   end
  350.   method random()
  351.     return ?self.theCollection
  352.   end
  353. end
  354.  
  355. class Vector : Collection()
  356.   method getElement(i)
  357.     return self.theCollection[i]
  358.   end
  359.   method setElement(i,v)
  360.     return self.theCollection[i] := v
  361.   end
  362. end
  363.  
  364. class Table : Vector(initialvalue,theCollection)
  365. initially
  366.   self.theCollection := table(self.initialvalue)
  367. end
  368.  
  369. #
  370. # The field theCollection is explicitly named so that subclasses of Stack
  371. # and Queue use these automatic initializations.  The / operator is used
  372. # to reduce the number of throw-away list allocations for subclasses which
  373. # >don't< inherit theCollection from Stack or Queue (e.g. class List).
  374. # It also allows initialization by constructor.  If one wanted to
  375. # guarantee that all Stacks start out empty but still allow class List
  376. # to be explicitly intitialized, one could remove the / here, and name
  377. # theCollection in class List, causing its initially section to override
  378. # the superclass with respect to the field theCollection.  I choose here
  379. # to maximize code sharing rather than protecting my Stack class.
  380. #
  381. # When allowing initialization by constructor one might consider
  382. # checking the type of the input to guarantee it conforms to the
  383. # type expected by the class.
  384. #
  385. class Stack : Collection(theCollection)
  386.   method push(value)
  387.     push(self.theCollection,value)
  388.   end
  389.   method pop()
  390.     return pop(self.theCollection)
  391.   end
  392. initially
  393.   /self.theCollection := []
  394. end
  395.  
  396. class Queue : Collection(theCollection)
  397.   method get()
  398.     return get(self.theCollection)
  399.   end
  400.   method put(value)
  401.     put(self.theCollection,value)
  402.   end
  403. initially
  404.   /self.theCollection := []
  405. end
  406.  
  407. class Deque : Queue : Stack()
  408. end
  409.  
  410. #
  411. # List inherits Queue's theCollection initialization, because Queue is the
  412. # first class on List's (transitively closed) superclass list to name
  413. # theCollection explicitly
  414. #
  415. class List : Deque : Vector()
  416.   method concat(l)
  417.     return List(self.theCollection ||| l)
  418.   end
  419. end
  420.  
  421. class Atom : Object(public val)
  422.   method asString()
  423.     return string(self.val)
  424.   end
  425.   method asInteger()
  426.     return integer(self.val)
  427.   end
  428.   method asReal()
  429.     return real(self.val)
  430.   end
  431. end
  432.  
  433. class Number : Atom ()
  434.   method plus(n)
  435.     return self.val + n$val()
  436.   end
  437.   method minus(n)
  438.     return self.val - n$val()
  439.   end
  440.   method times(n)
  441.     return self.val * n$val()
  442.   end
  443.   method divide(n)
  444.     return self.val / n$val()
  445.   end
  446. end
  447.  
  448. class Integer : Number()
  449. initially
  450.   if not (self.val := integer(self.val)) then
  451.     stop("can't make Integer from ",image(self.val))
  452. end
  453.  
  454. class Real : Number()
  455. initially
  456.   if not (self.val := real(self.val)) then
  457.     stop("can't make Real from ",image(self.val))
  458. end
  459.  
  460. class String : Vector : Atom()
  461.   method concat(s)
  462.     return self.theCollection || s
  463.   end
  464. end
  465. ##########
  466. fraction.iol
  467. class fraction(n,d)
  468.   method n()
  469.     return self.n
  470.   end
  471.   method d()
  472.     return self.d
  473.   end
  474.   method times(f)
  475.     return fraction(self.n * f$n(), self.d * f$d())
  476.   end
  477.   method asString()
  478.     return self.n||"/"||self.d
  479.   end
  480.   method asReal()
  481.     return real(self.n) / self.d
  482.   end
  483. initially
  484.   if self.d=0 then stop("fraction: denominator=0")
  485. end
  486. ##########
  487. idol.1
  488. .TH IDOL 1 "26 February 1990"
  489. .UC 4
  490. .SH NAME
  491. idol \- Icon-Derived Object Language
  492. .SH SYNOPSIS
  493. .B idol
  494. .B \-install
  495. .br
  496. .B idol
  497. [
  498. .B option...
  499. ]
  500. mainfile otherfiles
  501. [
  502. .B \-x
  503. arguments
  504. ]
  505. .SH DESCRIPTION
  506. .PP
  507. .I Idol
  508. is an object-oriented preprocessor for Version 7.5+ Icon.
  509. It is a front-end for
  510. .I icont(1)
  511. ; typically one invokes idol on
  512. a source file (extension .iol) which is translated into an
  513. Icon source file (extension .icn) which is translated into a
  514. file suitable for interpretation by the Icon interpreter.
  515. Each directory containing Idol source files should be initialized
  516. by 
  517. .B idol
  518. .B \-install
  519. prior to translating any user sources.
  520. Producing an executable is skipped when the first file on the
  521. list contains only classes.
  522. .PP
  523. The
  524. .B \-c
  525. option suppresses the linking phase normally done by
  526. .I Icont.
  527. .PP
  528. The
  529. .B \-t
  530. option suppresses
  531. .B all
  532. translation by
  533. .I Icont;
  534. it is useful on systems for which Icon does not support the
  535. .br
  536. .B system\(\)
  537. function.
  538. .PP
  539. The
  540. .B \-s
  541. option suppresses removal of
  542. .B \.icn
  543. files after translation by
  544. .I Icont;
  545. normally they are deleted after a successful translation.
  546. .PP
  547. The
  548. .B \-quiet
  549. option suppresses most Idol-specific console messages.
  550. .PP
  551. The
  552. .B \-install
  553. option installs the Idol
  554. .B environment
  555. .br
  556. in the current directory.
  557. .PP
  558. The
  559. .B \-strict
  560. option causes
  561. .I Idol
  562. to generate code which is paranoid about ensuring encapsulation.
  563. .PP
  564. The
  565. .B \-version
  566. option causes
  567. .I Idol
  568. to print out its version and date of creation, and then exit.
  569. .PP
  570. The second and following files on the command line may include
  571. extensions
  572. .B \.icn
  573. ,
  574. .B \.u1
  575. , and
  576. .B \.cl\.
  577. The first two Idol treats as
  578. Icon source code which should be translated and linked into the
  579. resulting executable.  Files with extension
  580. .B \.cl
  581. are treated as class names which are linked into the resulting executable.
  582. .PP
  583. .SH AUTHOR
  584. .PP
  585. Clinton Jeffery, cjeffery@cs.arizona.edu
  586. .PP
  587. .SH FILES
  588. .PP
  589. .nf
  590. idol                          The Idol translator itself.
  591. .br
  592. prog.iol                      Idol source files
  593. .br
  594. prog.icn                      Icon code (non-classes) from prog.iol
  595. .br
  596. idolcode.env/i_object.*       Icon code for the Idol object type
  597. .br
  598. idolcode.env/classname.icn    Icon files generated for each class
  599. .br
  600. idolcode.env/classname.u[12]  Translated class files
  601. .br
  602. idolcode.env/classname        Class specification/interface
  603. .fi
  604. .SH SEE ALSO
  605. .PP
  606. .br
  607. "Programming in Idol: An Object Primer"
  608. .br
  609. (U of Arizona Dept of CS Technical Report #90-10)
  610. .br
  611. serves as a user's guide and reference manual for Idol
  612. ##########
  613. idol.bat
  614. iconx idol %1 %2 %3 %4 %5 %6 %7 %8 %9
  615. idolt
  616. ##########
  617. idol.com
  618. $ ! VMS Idol invocation script for simple compiles
  619. $ iconx idol "-t" 'P1' 'P2' 'P3' 'P4' 'P5' 'P6' 'P7' 'P8' 'P9'
  620. $ icont "-Sr1000" "-Sg500" "-SF30" 'P1'
  621. ##########
  622. idol.doc
  623.  
  624.  
  625.  
  626.                 Programming in Idol: An Object Primer
  627.  
  628.                           Clinton L. Jeffery
  629.  
  630.                            March 14, 1990
  631.  
  632. Idol is an object-oriented extension and environment for the
  633. Icon programming language.  This document describes Idol in two parts.
  634. The first part presents Idol's object-oriented programming concepts
  635. as an integral tool with which a programmer maps a good program
  636. design into a good implementation.  As such, it serves as
  637. of "user's guide" for Idol's extensions to Icon.  Idol's
  638. object-oriented programming facilities are viewed within the
  639. broader framework of structured programming and modular design
  640. in general.  Idol's precise syntax and semantics are detailed in the
  641. second part, "An Icon-Derived Object Language", which serves as a
  642. reference manual.
  643.  
  644.  
  645.  
  646.  
  647.  
  648.              Object-Oriented Programming After a Fashion
  649.  
  650. Object-oriented programming means different things to different people.
  651. In Idol, object-oriented programming centers around encapsulation,
  652. inheritance, and polymorphism.  These key ideas are shared by most
  653. object-oriented languages as well as many languages that are not
  654. considered object-oriented.  This paper introduces these ideas and
  655. illustrates their use in actual code.  Idol is relevant in this
  656. discussion because programming concepts are more than mental
  657. exercises; they are mathematical notations by which programmers share
  658. their knowledge.
  659.  
  660. Object-oriented programming can be done in Smalltalk, C++, or
  661. assembler language for that matter, but this does not mean these
  662. programming notations are equally desirable.  Assembler languages
  663. are not portable.  For most programmers, Smalltalk uses an alien
  664. notation; Smalltalk programs also share the flaw that they do not
  665. work well in environments such as UNIX and DOS that consist of
  666. interacting programs written in many languages.  C++ has neither of
  667. these flaws, but the same low-level machine-oriented character
  668. that makes it efficient also makes C++ less than ideal as an
  669. algorithmic notation usable by nonexperts.
  670.  
  671. Idol owes most of its desirable traits to its foundation, the Icon
  672. programming language, developed at the University of Arizona
  673. [Griswold83].  In fact, Idol presents objects simply as a tool
  674. to aid in the writing of Icon programs. Idol integrates a concise,
  675. robust notation for object-oriented programming into a language
  676. considerably more advanced than C or Pascal.  Icon already uses a
  677. powerful notation for expressing a general class of algorithms. The
  678. purpose of Idol is to enhance that notation, not to get in the way.
  679.  
  680.  
  681.                              Key Concepts
  682.  
  683. This section describes the general concepts that Idol supplies
  684. to authors of large Icon programs.  The following section provides
  685. programming examples that employ these tools.  The reader is
  686. encouraged to refer back to this section when clarification in
  687. the examples section is needed.
  688.  
  689. The single overriding reason for object-oriented programming
  690. is the large program.  Simple programs can be easily written in
  691. any notation.  Somewhere between the 1,000-line mark and the
  692. 10,000-line mark most programmers can no longer keep track of their
  693. entire program at once.  By using a very high-level programming language,
  694. less lines of code are required; a programmer can write perhaps ten
  695. times as large a program and still be able to keep track of things.
  696. As programmers are required to write larger and larger programs,
  697. the benefit provided by very-high level languages does not keep up
  698. with program complexity.  This obstacle has been labelled the
  699. "software crisis", and object-oriented programming addresses this
  700. crisis.  In short, the goals of object-oriented programming are to
  701. reduce the amount of coding required to write very large programs and
  702. to allow code to be understood independently of the context of the
  703. surrounding program.  The techniques employed to achieve these goals
  704. are discussed below.
  705.  
  706.  
  707.                             Encapsulation
  708.  
  709. The primary concept advocated by object-oriented programming is the
  710. principle of encapsulation.  Encapsulation is the isolation, in the
  711. source code that a programmer writes, of a data representation and the code
  712. that manipulates the data representation.  In some sense, encapsulation
  713. is an assertion that no other routines in the program have "side-effects"
  714. with respect to the data structure in question.  It is easier to reason
  715. about encapsulated data because all of the source code that could affect
  716. that data is immediately present with its definition.
  717.  
  718. Encapsulation does for data structures what the procedure does for
  719. algorithms: it draws a line of demarcation in the program text, the
  720. outside of which is (or can be, or ought to be) irrelevant to the inside.
  721. We call an encapsulated data structure an object. Just as a set of
  722. named variables called parameters comprise the only interface between a
  723. procedure and the code that uses it, a set of named procedures called
  724. methods comprise the only interface between an object and the code that
  725. uses it.
  726.  
  727. This textual definition of encapsulation as a property of program
  728. source code accounts for the fact that good programmers can write
  729. encapsulated data structures in any language.  The problem is not
  730. capability, but verification.  In order to verify encapsulation some
  731. object-oriented languages, like C++, define an elaborate mechanism by
  732. which a programmer can govern the visibility of each data structure.
  733. Like Smalltalk, Idol instead attempts to simplify verification by
  734. preventing violations of encapsulation entirely.
  735.  
  736.  
  737.                              Inheritance
  738.  
  739. In large programs, the same or nearly the same data structures are
  740. used over and over again for a myriad of different purposes.  Similarly,
  741. variations on the same algorithms are employed by structure after
  742. structure.  In order to minimize redundancy, techniques are needed to
  743. support code sharing for both data structures and algorithms.
  744. Code is shared by related data structures by a programming concept
  745. called inheritance.
  746.  
  747. The basic premise of inheritance is simple: if I need to write code
  748. for a new data structure which is similar to one that's already
  749. written, I can specify the new structure by giving the differences
  750. between it and the old structure, instead of copying and then modifying
  751. the old structure's code.  Obviously there are times when the
  752. inheritance mechanism is not useful: if the two data structures are
  753. more different than they are similar, or if they are simple enough
  754. that inheritance would only confuse things, for example.
  755.  
  756. Inheritance addresses a variety of common programming problems found
  757. at different conceptual levels.  The most obvious software engineering
  758. problem it solves might be termed enhancement.  During the
  759. development of a program, its data structures may require extension
  760. via new state variables or new operations or both; inheritance is
  761. especially useful when both the original structure and the extension
  762. are used by the application.  Inheritance also supports
  763. simplification, or the reduction of a data structure's state variables
  764. or operations.  Simplification is analogous to argument culling after
  765. the fashion of the lambda calculus; it captures a logical relation
  766. between structures rather than a common situation in software
  767. development.  In general, inheritance may be used in source code to
  768. describe any sort of relational hyponymy, or special-casing; in Idol
  769. the collection of all inheritance relations defines a directed (not
  770. necessarily acyclic) graph.
  771.  
  772.  
  773.                              Polymorphism
  774.  
  775. From the perspective of the writer of related data structures,
  776. inheritance provides a convenient method for code sharing, but
  777. what about the code that uses objects?  Since objects are
  778. encapsulated, that code is not dependent upon the internals of
  779. the object at all, and it makes no difference to the client code
  780. whether the object in questions belongs to the original class or the
  781. inheriting class.
  782.  
  783. In fact, we can make a stronger statement.  Due to encapsulation,
  784. two different executions of some code that uses objects to implement
  785. a particular algorithm may operate on different objects that are
  786. not related by inheritance at all.  Such code may effectively
  787. be shared by any objects that happen to implement the operations
  788. that the code invokes.  This facility is called polymorphism, and
  789. such algorithms are called generic.  This feature is found in
  790. non-object oriented languages; in object-oriented languages it is
  791. a natural extension of encapsulation.
  792.  
  793.  
  794.                           Object Programming
  795.  
  796. The concepts introduced above are used in many programming languages
  797. in one form or another.  The following text presents these concepts
  798. in the context of actual Idol code.  This serves a dual purpose:
  799. it should clarify the object model adopted by Idol as well as
  800. provide an initial impression of these concepts' utility in coding.
  801. In order to motivate the constructs provided by Idol, our example
  802. begins by contrasting conventional Icon code with Idol code which
  803. implements the same behavior.  The semantics of the Idol code given
  804. here is defined by the Idol reference manual, included later in this
  805. document in the section entitled, "An Icon-Derived Object Language".
  806.  
  807.                             Before Objects
  808.  
  809. In order to place Idol objects in their proper context, the first
  810. example is taken from from regular Icon.  Suppose I am writing some
  811. text-processing application such as a text editor.  Such applications
  812. need to be able to process Icon structures holding the contents of
  813. various text files.  I might begin with a simple structure like the
  814. following:
  815.  
  816. record buffer(filename,text,index)
  817.  
  818. where filename is a string, text is a list of strings
  819. corresponding to lines in the file, and index is a marker for
  820. the current line at which the buffer is being processed.  Icon record
  821. declarations are global; in principle, if the above declaration needs
  822. to be changed, the entire program must be rechecked.  A devotee of
  823. structured programming would no doubt write Icon procedures to read
  824. the buffer in from a file, write it out to a file, examine, insert
  825. and delete individual lines, etc.  These procedures, along with the
  826. record declaration given above, can be kept in a separate source file
  827. (buffer.icn) and understood independently of the program(s) in
  828. which they are used.  Here is one such procedure:
  829.  
  830.  
  831. # read a buffer in from a file
  832. procedure read_buffer(b)
  833.   f := open(b.filename) | fail
  834.   b.text := [ ]
  835.   b.position := 1
  836.   every put(b.text,!f)
  837.   close(f)
  838.   return b
  839. end
  840.  
  841. There is nothing wrong with this example; in fact its similarity to the
  842. object-oriented example that follows demonstrates that a good, modular
  843. design is the primary effect encouraged by object-oriented programming.
  844. Using a separate source file to contain a record type and those
  845. procedures which operate on that type allows an Icon programmer to
  846. maintain a voluntary encapsulation of that type.
  847.  
  848.                             After Objects
  849.  
  850. Here is the same buffer abstraction coded in Idol.  This example
  851. lays the groundwork for some more substantial techniques to follow.
  852.  
  853. class buffer(public filename,text,index)
  854.   # read a buffer in from a file
  855.   method read()
  856.     f := open(self.filename) | fail
  857.     self$erase()
  858.     every put(self.text,!f)
  859.     close(f)
  860.     return
  861.   end
  862.   # write a buffer out to a file
  863.   method write()
  864.     f := open(self.filename,"w") | fail
  865.     every write(f,!self.text)
  866.     close(f)
  867.   end
  868.   # insert a line at the current index
  869.   method insert(s)
  870.     if self.index = 1 then {
  871.       push(self.text,s)
  872.     } else if self.index > *self.text then {
  873.       put(self.text,s)
  874.     } else {
  875.       self.text := self.text[1:self.index]|||[s]|||self.text[self.index:0]
  876.     }
  877.     self.index +:= 1
  878.     return
  879.   end
  880.   # delete a line at the current index
  881.   method delete()
  882.     if self.index > *self.text then fail
  883.     rv := self.text[self.index]
  884.     if self.index=1 then pull(self.text)
  885.     else if self.index = *self.text then pop(self.text)
  886.     else self.text := self.text[1:self.index]|||self.text[self.index+1:0]
  887.     return rv
  888.   end
  889.   # move the current index to an arbitrary line
  890.   method goto(l)
  891.     if (0 <= l) & (l <= self.index+1) then return self.index := l
  892.   end
  893.   # return the current line and advance the current index
  894.   method forward()
  895.     if self.index > *self.text then fail
  896.     rv := self.text[self.index]
  897.     self.index +:= 1
  898.     return rv
  899.   end
  900.   method erase()
  901.     self.text     := [ ]
  902.     self.index    := 1
  903.   end
  904. initially
  905.   if \ (self.filename) then {
  906.     if not self$read() then self$erase()
  907.   } else {
  908.     self.filename := "*scratch*"
  909.     self$erase()
  910.   }
  911. end
  912.  
  913.  
  914. This first example is not complex enough to illustrate the full
  915. object-oriented style, but its a start.  Pertaining to the
  916. general concepts introduced above, we can make the following
  917. initial observations:
  918.  
  919. Polymorphism. A separate name space for each class's methods
  920. makes for shorter names.  The same method name can be used in each
  921. class that implements a given operation.  This notation is more
  922. concise than is possible with standard Icon procedures.  More
  923. importantly it allows algorithms to operate correctly upon objects of
  924. any class which implements the operations required by the algorithm.
  925. Constructors.  A section of code is executed automatically when
  926. the constructor is called, allowing initialization of fields to values
  927. other than &null.  Of course, this could be simulated in Icon
  928. by writing a procedure that had the same effect; the value of the
  929. constructor is that it is automatic; the programmer is freed from the
  930. responsibility of remembering to call this code everywhere objects are
  931. created in the client program(s).  This tighter coupling of memory
  932. allocation and its corresponding initialization removes one more
  933. source of program errors, especially on multiprogrammer projects.
  934.  
  935.  
  936. These two observations share a common theme: the net effect is that
  937. each piece of data is made responsible for its own behavior in the
  938. system. Although this first example dealt with simple line-oriented
  939. text files, the same methodology applies to more abstract entities
  940. such as the components of a compiler's grammar (This example
  941. is taken from the Idol translator itself, which provides another
  942. extended example of polymorphism and inheritance.).
  943.  
  944. Idol's code sharing facilities are illustrated if we extend the above
  945. example.  Suppose the application is more than just a text editor---
  946. it includes word-associative databases such as a dictionary,
  947. bibliography, spell-checker, thesaurus, etc.  These various databases
  948. can be represented internally using Icon tables.  The table entries
  949. for the databases vary, but the databases all use string keyword
  950. lookup.  As external data, the databases can be stored in text files,
  951. one entry per line, with the keyword at the beginning.  The format
  952. of the rest of the line varies from database to database.
  953.  
  954. Although all these types of data are different, the code used to
  955. read the data files can be shared, as well as the initial construction
  956. of the tables.  In fact, since we are storing our data one entry per
  957. line in text files, we can use the code already written for buffers
  958. to do the file i/o itself.
  959.  
  960.  
  961. class buftable : buffer()
  962.   method read()
  963.     self$buffer.read()
  964.     tmp := table()
  965.     every line := !self.text do
  966.       line ? { tmp[tab(many(&letters))] := line | fail }
  967.     self.text := tmp
  968.     return
  969.   end
  970.   method lookup(s)
  971.     return self.text[s]
  972.   end
  973. end
  974.  
  975.  
  976. This concise example shows how little must be written to achieve
  977. data structures with vastly different behavioral characteristics,
  978. by building on code that is already written.  The superclass
  979. read() operation is one important step of the subclass
  980. read() operation; this technique is common enough to have a
  981. name: it is called method combination in the literature. It
  982. allows one to view the subclass as a transformation of the
  983. superclass.  The buftable class is given in its entirety, but
  984. our code sharing example is not complete: what about the data
  985. structures required to support the databases themselves?  They are all
  986. variants of the buftable class, and a set of possible
  987. implementations is given below.  Note that the formats presented are
  988. designed to illustrate code sharing; clearly, an actual application
  989. might make different choices.
  990.  
  991.                             Bibliographies
  992.  
  993. Bibliographies might consist of a keyword followed by an uninterpreted
  994. string of information.  This imposes no additional structure on the
  995. data beyond that imposed by the buftable class.  An example
  996. keyword would be Jeffery90.
  997.  
  998.  
  999. class bibliography : buftable()
  1000. end
  1001.  
  1002.  
  1003.  
  1004.                             Spell-checkers
  1005.  
  1006. The database for a spell-checker is presumably just a list of words,
  1007. one per line; the minimal structure required by the buftable
  1008. class given above.  Some classes exist to introduce new terminology
  1009. rather than define a new data structure.  In this case we introduce
  1010. a lookup operation which may fail, for use in tests.  In addition,
  1011. since many spell-checking systems allow user definable dictionaries
  1012. in addition to their central database, we allow spellChecker
  1013. objects to chain together for the purpose of looking up words.
  1014.  
  1015.  
  1016. class spellChecker : buftable(parentSpellChecker)
  1017.   method spell(s)
  1018.     return \ (self.text[s]) | (\ (self.parentSpellChecker))$spell(s)
  1019.   end
  1020. end
  1021.  
  1022.  
  1023.  
  1024.                              Dictionaries
  1025.  
  1026. Dictionaries are slightly more involved.  Each entry might consist of a
  1027. part of speech, an etymology, and an arbitrary string of uninterpreted
  1028. text comprising a definition for that entry, separated by semicolons.
  1029. Since each such entry is itself a structure, a sensible decomposition
  1030. of the dictionary structure consists of two classes: one that manages
  1031. the table and external file i/o, and one that handles the manipulation
  1032. of dictionary entries, including their decoding and encoding as
  1033. strings.
  1034.  
  1035.  
  1036. class dictionaryentry(word,pos,etymology,definition)
  1037.   method decode(s) # decode a dictionary entry into its components
  1038.     s ? {
  1039.       self.word       := tab(upto(';'))
  1040.       move(1)
  1041.       self.pos        := tab(upto(';'))
  1042.       move(1)
  1043.       self.etymology  := tab(upto(';'))
  1044.       move(1)
  1045.       self.definition := tab(0)
  1046.     }
  1047.   end
  1048.   method encode()  # encode a dictionary entry into a string
  1049.     return self.word||";"||self.pos||";"||self.etymology||";"||self.definition
  1050.   end
  1051. initially
  1052.   if /self.pos then {
  1053.     # constructor was called with a single string argument
  1054.     self$decode(self.word)
  1055.   }
  1056. end
  1057.  
  1058. class dictionary : buftable()
  1059.   method read()
  1060.     self$buffer.read()
  1061.     tmp := table()
  1062.     every line := !self.text do
  1063.       line ? { tmp[tab(many(&letters))] := dictionaryentry(line) | fail }
  1064.     self.text := tmp
  1065.   end
  1066.   method write()
  1067.     f := open(b.filename,"w") | fail
  1068.     every write(f,(!self.text)$encode())
  1069.     close(f)
  1070.   end
  1071. end
  1072.  
  1073.  
  1074.                                Thesauri
  1075.  
  1076. Although an oversimplification, one might conceive of a thesauri as a
  1077. list of entries, each of which consists of a comma-separated list of
  1078. synonyms followed by a comma-separated list of antonyms, with a
  1079. semicolon separating the two lists.  Since the code for such a
  1080. structure is nearly identical to that given for dictionaries above,
  1081. we omit it here (but one might reasonably capture a generalization
  1082. regarding entries organized as fields separated by semicolons).
  1083.  
  1084.  
  1085.                Objects and Icon Programming Techniques
  1086.  
  1087. In examining any addition to a language as large as Icon, a
  1088. significant question is how that addition relates to the rest of the
  1089. language. In particular, how does object-oriented programming fit into
  1090. the suite of advanced techniques used regularly by Icon programmers?
  1091. Previous sections of this document expound objects as an
  1092. organizational tool, analogous but more effective than the use of
  1093. separate compilation to achieve program modularity.  Object-oriented
  1094. programming goes considerably beyond that viewpoint.
  1095.  
  1096. Whether viewed dynamically or statically, the primary effect achieved
  1097. by object-oriented programming is the subdivision of program data in
  1098. parallel with the code.  Icon already provides a variety of tools that
  1099. achieve related effects:
  1100.  
  1101. Local and Static Variables in Icon procedures are the simplest
  1102. imaginable parallel association of data and code.  We do not discuss
  1103. them further, although they are by no means insignificant.
  1104. Records allow a simple form of user-defined types. They provide
  1105. a useful abstraction, but keeping records associated with the right
  1106. pieces of code is still the job of the programmer.
  1107. String Scanning creates scanning environments.  These are very
  1108. useful, but not very general: not all problems can be cast as
  1109. string operations.
  1110. Co-expressions save a program state for later evaluation.  This
  1111. powerful facility has a sweeping range of uses, but unfortunately it
  1112. is a relatively expensive mechanism that is frequently misused to
  1113. achieve a simple effect.
  1114.  
  1115.  
  1116. Objects and classes, if they are successful, allow a significant
  1117. generalization of the techniques developed around the above
  1118. language mechanisms.  Objects do not replace these language
  1119. mechanisms, but in many cases presented below they provide an
  1120. attractive alternative means of achieving similar effects.
  1121.  
  1122.                          Objects and records
  1123.  
  1124. Objects are simply records whose field accesses are voluntarily
  1125. limited to a certain set of procedures.
  1126.  
  1127.                   Objects and scanning environments
  1128.  
  1129. String scanning in Icon is another example of associating a piece of
  1130. data with the code that operates on it.  In an Icon scanning
  1131. expression of the form e1 ? e2, the result of evaluating
  1132. e1 is used implicitly in e2 via a variety of scanning
  1133. functions.  In effect, the scanning operation defines a scope in which
  1134. state variables &subject and &pos are redefined.
  1135. [Walker86] proposes an extension to Icon allowing
  1136. programmer-defined scanning environments. The extension involves a new
  1137. record data type augmented by sections of code to be executed upon
  1138. entry, resumption, and exit of the scanning environment.  The Icon
  1139. scanning operator was modified to take advantage of the new facility
  1140. when its first argument was of the new environment data type.
  1141.  
  1142. While objects cannot emulate Icon string scanning syntactically, they
  1143. generalize the concept of the programmer-defined scanning environment.
  1144. Classes in the Idol standard library include a wide variety of
  1145. scanning environments in addition to conventional strings.  The
  1146. variation is not limited to the type of data scanned; it also includes
  1147. the form and function of the scanning operations.  The form of
  1148. scanning operations available are defined by the state variables they
  1149. access; in the case of Icon's built-in string scanning, a single
  1150. string and a single integer index into that string.
  1151.  
  1152. There is no reason that a scanning environment cannot maintain a more
  1153. complex state, such as an input string, an output string, and a pair
  1154. of indices and directions for each string.  Rather than illustrate
  1155. the use of objects to construct scanning environments with such an
  1156. abstract model, a concrete example is presented below.
  1157.  
  1158.                             List scanning
  1159.  
  1160. List scanning is a straightforward adaptation of string scanning to
  1161. the list data type.  It consists of a library class named
  1162. ListScan that implements the basic scanning operations, and
  1163. various user classes that include the scanning expressions.  This
  1164. format is required due to Idol's inability to redefine the semantics
  1165. of the ? operator or to emulate its syntax in any reasonable
  1166. way.  The state maintained during a list scan consists of
  1167. Subject and Pos,  analogous to &subject and
  1168. &pos, respectively.
  1169.  
  1170. ListScan defines analogies to the basic scanning functions of
  1171. Icon, e.g. tab, upto, many, any, etc.  These
  1172. functions are used in methods  of a ListScan client class, which
  1173. in turn defines itself as a subclass of ListScan.  A client such as:
  1174.  
  1175. class PreNum : ListScan()
  1176.   method scan()
  1177.     mypos := self.Pos
  1178.     suspend self$tab(self$upto(numeric))
  1179.     self.Pos := mypos
  1180.   end
  1181. end
  1182.  
  1183. may be used in an expression such as
  1184.  
  1185. (PreNum(["Tucson", "Pima", 15.0, [ ], "3"]))$scan()
  1186.  
  1187. producing the result ["Tucson", "Pima"].  The conventional Icon
  1188. string scanning analogy would be: "abc123" ? tab(upto(&digits)),
  1189. which produces the result "abc".  Note that ListScan
  1190. methods frequently take list-element predicates as arguments where
  1191. their string scanning counterparts take csets.  In the above example,
  1192. the predicate numeric supplied to upto is an Icon
  1193. function, but predicates may also be arbitrary user-defined procedures.
  1194.  
  1195. The part of the Idol library ListScan class required to
  1196. understand the previous example is presented below.  This code is
  1197. representative of user-defined scanning classes allowing pattern
  1198. matching over arbitrary data structures in Idol.  Although
  1199. user-defined scanning is more general than Icon's built-in scanning
  1200. facilities, the scanning methods given below are always
  1201. activated in the context of a specific environment.  Icon string
  1202. scanning functions can be supplied an explicit environment using
  1203. additional arguments to the function.
  1204.  
  1205.  
  1206. class ListScan(Subject,Pos)
  1207.   method tab(i)
  1208.     if i<0 then i := *self.Subject+1-i
  1209.     if i<0 | i>*self.Subject+1 then fail
  1210.     origPos := self.Pos
  1211.     self.Pos := i
  1212.     suspend self.Subject[origPos:i]
  1213.     self.Pos := origPos
  1214.   end
  1215.   method upto(predicate)
  1216.     origPos := self.Pos
  1217.     every i := self.Pos to *(self.Subject) do {
  1218.       if predicate(self.Subject[i]) then suspend i
  1219.     }
  1220.     self.Pos := origPos
  1221.   end
  1222. initially
  1223.   /(self.Subject) := [ ]
  1224.   /(self.Pos) := 1
  1225. end
  1226.  
  1227.  
  1228.  
  1229.                       Objects and co-expressions
  1230.  
  1231. Objects cannot come close to providing the power of co-expressions,
  1232. but they do provide a more efficient means of achieving well-known
  1233. computations such as parallel expression evaluation that have been
  1234. promoted as uses for co-expressions.  In particular, a co-expression
  1235. is able to capture implicitly the state of a generator for later
  1236. evaluation; the programmer is saved the trouble of explicitly coding
  1237. what can be internally and automatically performed by Icon's
  1238. expression mechanism.  While objects cannot capture a generator state
  1239. implicitly, the use of library objects mitigates the cost of
  1240. explicitly encoding the computation to be performed, as an
  1241. alternative to the use of co-expressions.  The use of objects also is
  1242. a significant alternative for implementations of Icon in which
  1243. co-expressions are not available or memory is limited.
  1244.  
  1245.                          Parallel evaluation
  1246.  
  1247. In [Griswold87], co-expressions are used to obtain the results
  1248. from several generators in parallel:
  1249.  
  1250. decimal   := create(0 to 255)
  1251. hex       := create(!"0123456789ABCDEF" || !"0123456789ABCDEF")
  1252. octal     := create((0 to 3) || (0 to 7) || (0 to 7))
  1253. character := create(image(!&cset))
  1254. while write(right(@decimal,3)," ",@hex," ",@octal," ",@character)
  1255.  
  1256.  
  1257. For the Idol programmer, one alternative to using co-expressions would
  1258. be to link in the following code from the Idol standard library:
  1259.  
  1260. procedure sequence(bounds[ ])
  1261.   return Sequence(bounds)
  1262. end
  1263.  
  1264. class Sequence(bounds,indices)
  1265.   method max(i)
  1266.     elem := self.bounds[i]
  1267.     return (type(elem)== "integer",elem) | *elem-1
  1268.   end
  1269.   method elem(i)
  1270.     elem := self.bounds[i]
  1271.     return (type(elem)== "integer",self.indices[i]) | elem[self.indices[i]+1]
  1272.   end
  1273.   method activate()
  1274.     top := *(self.indices)
  1275.     if self.indices[1] > self$max(1) then fail
  1276.     s := ""
  1277.     every i := 1 to top do {
  1278.       s ||:= self$elem(i)
  1279.     }
  1280.     repeat {
  1281.        self.indices[top] +:= 1
  1282.        if top=1 | (self.indices[top] <= self$max(top)) then break
  1283.        self.indices[top] := 0
  1284.        top -:= 1
  1285.     }
  1286.     return s
  1287.   end
  1288. initially
  1289.   / (self.indices) := list(*self.bounds,0)
  1290. end
  1291.  
  1292.  
  1293. On the one hand, the above library code is neither terse nor general
  1294. compared with co-expressions. This class does, however, allow the
  1295. parallel evaluation problem described previously to be coded as:
  1296.  
  1297. decimal   := sequence(255)
  1298. hex       := sequence("0123456789ABCDEF","0123456789ABCDEF")
  1299. octal     := sequence(3,7,7)
  1300. character := sequence(string(&cset))
  1301. while write(right($@decimal,3)," ",$@hex," ",$@octal," ",image($@character))
  1302.  
  1303.  
  1304. $@ is the unary Idol meta-operator that invokes the
  1305. activate() operation. Since the sequence class is already
  1306. written and available, its use is an attractive alternative to
  1307. co-expressions in many settings.  For example, a general class of
  1308. label generators (another use of co-expressions cited in
  1309. [Griswold87]) is defined by the following library class:
  1310.  
  1311. class labelgen : Sequence(prefix,postfix)
  1312.   method activate()
  1313.     return self.prefix||self$Sequence.activate()||self.postfix
  1314.   end
  1315. initially
  1316.   /(self.prefix) := ""
  1317.   /(self.postfix) := ""
  1318.   /(self.bounds)  := [50000]
  1319. end
  1320.  
  1321. After creation of a label generator object (e.g.
  1322. label := labelgen("L",":")), each resulting label is obtained
  1323. via $@label. The sequence defined by this example is
  1324.  
  1325.         L0:
  1326.         L1:
  1327.         ...
  1328.         L50000:
  1329.  
  1330.  
  1331.                               Conclusion
  1332.  
  1333. Idol presents object programming as a collection of tools to reduce
  1334. the complexity of large Icon programs.  These tools are encapsulation,
  1335. inheritance, and polymorphism.  Since a primary goal of Idol is to
  1336. promote code sharing and reuse, a variety of specific programming
  1337. problems have elegant solutions available in the Idol class library.
  1338.  
  1339.  
  1340.                    An Icon-Derived Object Language
  1341.  
  1342. This section serves as the language reference manual for Idol.  Idol
  1343. is a preprocessor for Icon which implements a means of associating a
  1344. piece of data with the procedures which manipulate it.  The primary
  1345. benefits to the programmer are thus organizational.  The Icon
  1346. programmer may view Idol as providing an augmented record type in
  1347. which field accesses are made not directly on the records' fields, but
  1348. rather through a set of procedures associated with the type.
  1349.  
  1350.  
  1351.                                Classes
  1352.  
  1353. Since Idol implements ideas found commonly in object-oriented
  1354. programming languages, its terminology is taken from that domain.  The
  1355. augmented record type is called a "class".  The syntax of a class is:
  1356.  
  1357.  
  1358. class foo(field1,field2,field3,...)
  1359.    # procedures to access
  1360.    # class foo objects
  1361.  
  1362. [code to initialize class foo objects]
  1363. end
  1364.  
  1365.  
  1366. In order to emphasize the difference between ordinary Icon procedures
  1367. and the procedures which manipulate class objects, these procedures
  1368. are called "methods" (the term is again borrowed from the
  1369. object-oriented community).  Nevertheless, the syntax of a method is
  1370. that of a procedure:
  1371.  
  1372.  
  1373. method bar(param1,param2,param3,...)
  1374.  
  1375.    # Icon code which may access
  1376.    # fields of a class foo object
  1377. end
  1378.  
  1379.  
  1380. Since execution of a class method is always associated with a given
  1381. object of that class, the method has access to an implicit variable
  1382. called self which is a record containing fields whose names are
  1383. those given in the class declaration.  References to the self variable
  1384. look just like normal record references; they use the dot (.)
  1385. operator.  In addition to methods, classes may also contain regular
  1386. Icon procedure, global, and record declarations; such declarations
  1387. have the standard semantics and exist in the global Icon name space.
  1388.  
  1389.  
  1390.                                Objects
  1391.  
  1392. Like records, instances of a class type are created with a constructor
  1393. function whose name is that of the class.  Instances of a class are
  1394. called objects, and their fields may be initialized explicitly in the
  1395. constructor in exactly the same way as for records.  For example,
  1396. after defining a class foo(x,y) one may write:
  1397.  
  1398.  
  1399. procedure main()
  1400.  
  1401.   f := foo(1,2)
  1402. end
  1403.  
  1404.  
  1405. The fields of an object need not be initialized by the class
  1406. constructor.  For many objects it is more logical to initialize their
  1407. fields to some standard value.  In this case, the class declaration
  1408. may include an "initially" section after its methods are defined and
  1409. before its end.
  1410.  
  1411. This section begins with a line containing the word "initially" and
  1412. then contains lines which are executed whenever an object of that
  1413. class is constructed.  These lines may reference and assign to the
  1414. class fields as if they were normal record fields for the object being
  1415. constructed.  The "record" being constructed is named self;
  1416. more on self later.
  1417.  
  1418. For example, suppose one wished to implement an enhanced table type
  1419. which permitted sequential access to elements in the order they were
  1420. inserted into the table.  This can be implemented by a combination of
  1421. a list and a table, both of which would initialized to the appropriate
  1422. empty structure:
  1423.  
  1424.  
  1425. class taque(l,t) # pronouned `taco'
  1426.  
  1427.   # methods to manipulate taques,
  1428.   # e.g. insert, lookup, foreach...
  1429.  
  1430. initially
  1431.   self.l := [ ]
  1432.   self.t := table()
  1433. end
  1434.  
  1435.  
  1436. And in such a case one can create objects without including arguments
  1437. to the class constructor:
  1438.  
  1439.  
  1440. procedure main()
  1441.  
  1442.   mytaque := taque()
  1443. end
  1444.  
  1445.  
  1446. In the absence of an initially section, missing arguments to a
  1447. constructor default to the null value.  Together with an initially
  1448. section, the class declaration looks rather like a procedure that
  1449. constructs objects of that class.  Note that one may write classes
  1450. with some fields that are initialized explicitly by the constructor
  1451. and other fields are initialized automatically in the initially
  1452. section.  In this case one must either declare the automatically
  1453. initialized fields after those that are initialized in the
  1454. constructor, or insert &null in the positions of the
  1455. automatically initialized fields in the constructor.
  1456.  
  1457.  
  1458.  
  1459.                           Object Invocation
  1460.  
  1461. Once one has created an object with a class constructor, one
  1462. manipulates the object by invoking methods defined by its class.
  1463. Since objects are both procedures and data, object invocation is
  1464. similar to both a procedure call and a record access.  The dollar
  1465. ($) operator invokes one of an object's methods.  It used
  1466. similarly to the dot (.) operator used to access record fields.
  1467. Using the taque example:
  1468.  
  1469.  
  1470. procedure main()
  1471.   mytaque := taque()
  1472.   mytaque$insert("greetings","hello")
  1473.   mytaque$insert(123)
  1474.   every write(mytaque$foreach())
  1475.   if \(mytaque$lookup("hello"))
  1476.     then write(", world")
  1477. end
  1478.  
  1479.  
  1480. Note that direct access to an object's fields using the usual dot (.)
  1481. operator is not possible outside of a method of the appropriate class.
  1482. Attempts to reference mystack.l in procedure main() would result in
  1483. a runtime error (invalid field name).  Within a class method, the
  1484. implicit variable self allows access to the object's fields in
  1485. the usual manner.  The taque insert method is thus:
  1486.  
  1487.  
  1488.   method insert(x,key)
  1489.     /key := x
  1490.     put(self.l,x)
  1491.     self.t[key] := x
  1492.   end
  1493.  
  1494.  
  1495. The self variable is both a record and an object.  It allows field
  1496. access just like a record, as well as method invocation like any other
  1497. object.  Thus class methods can use self to invoke other class methods
  1498. without any special syntax.
  1499.  
  1500.  
  1501.  
  1502.                              Inheritance
  1503.  
  1504. In many cases, two classes of objects are very similar.  In
  1505. particular, many classes can be thought of simply as enhancements of
  1506. some class that has already been defined.  Enhancements might take the
  1507. form of added fields, added methods, or both.  In other cases a class
  1508. is just a special case of another class.  For example, if one had
  1509. defined a class fraction(numerator, denominator), one might want to
  1510. define a class inverses(denominator) whose behavior was identical to
  1511. that of a fraction, but whose numerator was always 1.
  1512.  
  1513. Idol supports both of these ideas with the concept of inheritance.
  1514. When the definition of a class is best expressed in terms of the
  1515. definition of another class or classes, we call that class a subclass
  1516. of the other classes.  This corresponds to the logical relation of
  1517. hyponymy. It means an object of the subclass can be manipulated just
  1518. as if it were an object of one of its defining classes.  In practical
  1519. terms it means that similar objects can share the code that
  1520. manipulates their fields. The syntax of a subclass is
  1521.  
  1522.  
  1523. class foo : superclasses (fields...)
  1524.  
  1525. # methods
  1526. [optional initially section]
  1527. end
  1528.  
  1529.  
  1530.  
  1531.                          Multiple Inheritance
  1532.  
  1533. There are times when a new class might best be described as a
  1534. combination of two or more classes.  Idol classes may have more than
  1535. one superclass, separated by colons in the class declaration.  This is
  1536. called multiple inheritance.
  1537.  
  1538. Subclasses define a record type consisting of all the fieldnames found
  1539. in the class itself and in all its superclasses.  The subclass has
  1540. associated methods consisting of those in its own body, those in the
  1541. first superclass which were not defined in the subclass, those in the
  1542. second superclass not defined in the subclass or the first superclass,
  1543. and so on.  Fields are initialized either by the constructor or by the
  1544. initially section of the first class of the class:superclass list in
  1545. which the field is defined.  For example, to define a class of
  1546. inverses in terms of a class fraction(numerator,denominator) one
  1547. would write:
  1548.  
  1549.  
  1550. class inverse : fraction (denominator)
  1551. initially
  1552.   self.numerator := 1
  1553. end
  1554.  
  1555.  
  1556. Objects of class inverse can be manipulated using all the methods
  1557. defined in class fraction; the code is actually shared by both classes
  1558. at runtime.
  1559.  
  1560. Viewing inheritance as the addition of fieldnames and methods of
  1561. superclasses not already defined in the subclass is the opposite of
  1562. the more traditional object-oriented view that a subclass starts with
  1563. an instance of the superclass and augments or overrides portions of
  1564. the definition with code in the subclass body.  Idol's viewpoint adds
  1565. quite a bit of leverage, such as the ability to define classes which
  1566. are subclasses of each other.  This feature is described further below.
  1567.  
  1568.  
  1569.                     Invoking Superclass Operations
  1570.  
  1571. When a subclass defines a method of the same name as a method defined
  1572. in the superclass, invocations on subclass objects always result in
  1573. the subclass' version of the method.  This can be overridden by
  1574. explicitly including the superclass name in the invocation:
  1575.  
  1576. object$superclass.method(parameters)
  1577.  
  1578. This facility allows the subclass method to do any additional work
  1579. required for added fields before or after calling an appropriate
  1580. superclass method to achieve inherited behavior.  The result is
  1581. frequently a chain of inherited method invocations.
  1582.  
  1583.  
  1584.  
  1585.                             Public Fields
  1586.  
  1587.  
  1588. As noted above, there is a strong correspondence between records and
  1589. classes.  Both define new types which extend Icon's built in
  1590. repertoire.  For simple jobs, records are slightly faster as well as
  1591. more convenient: the user can directly read and write a record's
  1592. fields by name.
  1593.  
  1594. Classes, on the other hand, promote the re-use of code and reduce the
  1595. complexity required to understand or maintain large, involved
  1596. structures.  They should be used especially when manipulating
  1597. composite structures ontaining mixes of structures as elements, e.g.
  1598. lists containing tables, sets, and lists in various positions.
  1599.  
  1600. Sometimes it would be really nice to access fields in an object
  1601. directly, as with records.  An example from the Idol program itself is
  1602. the name field associated with methods and classes---it is a
  1603. string which is intended to be read outside the object.  One can
  1604. always implement a method which returns (or assigns, for that matter)
  1605. a field value, but this gets tedious.  Idol currently supports
  1606. read-only access to fields via the public keyword.  If
  1607. public precedes a fieldname in a class declaration, Idol
  1608. automatically generates a method of the same name which dereferences
  1609. and returns the field.  For example, the declaration
  1610.  
  1611. class sinner(pharisee,public publican)
  1612.  
  1613. generates code equivalent to the following class method in addition
  1614. to any explicitly defined methods:
  1615.  
  1616.   method publican()
  1617.     return .(self.publican)
  1618.   end
  1619.  
  1620.  
  1621. This feature, despite its utility and the best of intentions, makes it
  1622. possible to subvert object encapsulation: it should not be
  1623. used with fields whose values are structures, since the structure
  1624. could then be modified from the outside.  When invoked with the
  1625. -strict option, Idol generates code for public methods which
  1626. checks for a scalar type at runtime before returning the field.
  1627.  
  1628.  
  1629.  
  1630.                 Superclass Cycles and Type Equivalence
  1631.  
  1632. In many situations, there are several ways to represent the same
  1633. abstract type.  Two-dimensional points might be represented by
  1634. Cartesian coordinates x and y, or equivalently by radial coordinates
  1635. expressed as degree d and radian r.  If one were implementing classes
  1636. corresponding to these types there is no reason why one of them should
  1637. be considered a subclass of the other.  The types are truly
  1638. interchangeable and equivalent.
  1639.  
  1640. In Idol, expressing this
  1641. equivalence is simple and direct.  In defining classes Cartesian
  1642. and Radian we may declare them to be superclasses of each other:
  1643.  
  1644. class Cartesian : Radian (x,y)
  1645. # code which manipulates objects using cartesian coordinates
  1646. end
  1647.  
  1648. class Radian : Cartesian (d,r)
  1649. # code which manipulates objects using radian coordinates
  1650. end
  1651.  
  1652. These superclass declarations make the two types equivalent names for
  1653. the same type of object; after inheritance, instances of both classes
  1654. will have fields x,y,d, and r, and support the same set of operations.
  1655.  
  1656. Equivalent types each have their own constructor given by their class
  1657. name; although they export the same set of operations, the actual
  1658. procedures invoked by the different instances may be different.  For
  1659. example, if both classes define an implementation of a method
  1660. print, the method invoked by a given instance depends on
  1661. which constructor was used when the object was created.
  1662.  
  1663. If a class inherits any methods from one of its equivalent
  1664. classes, it is responsible for initializing the state of all
  1665. the fields used by those methods in its own constructor, and
  1666. maintaining the state of the inherited fields when its methods make
  1667. state changes to its own fields.  In the geometric example given
  1668. above, in order for class Radian to use any methods inherited
  1669. from class Cartesian, it must at least initialize x and y explicity
  1670. in its constructor from calculations on its d and r parameters.
  1671. In general, this added responsibility is minimized in those classes
  1672. which treat an object's state as a value rather than a structure.
  1673.  
  1674. The utility of equivalent types expressed by superclass cycles remains
  1675. to be seen.  At the least, they provide a convenient way to write
  1676. several alternative constructors for the same class of objects.
  1677. Perhaps more importantly, their presence in Idol causes us to question
  1678. the almost religious dogmatism that the superclass graph must always
  1679. be acyclic.
  1680.  
  1681.  
  1682.  
  1683.                               Miscellany
  1684.  
  1685. Idol supports some shorthand for convenient object invocation.  In
  1686. particular, if a class defines methods named size, foreach, random,
  1687. or activate, these methods can be invoked by a modified version of
  1688. the usual Icon operator:
  1689.  
  1690.  
  1691. $*x is equivalent to x$size()
  1692. $?x is equivalent to x$random()
  1693. $!x is equivalent to x$foreach()
  1694. $@x is equivalent to x$activate()
  1695.  
  1696.  
  1697. Other operators may be added to this list.  If x is an identifier
  1698. it may be used directly; if it is a more complex expression (such as a
  1699. function call) it should be parenthesized, e.g.
  1700. $*(complex_expression()).
  1701. Parentheses are also required in the case of invoking an object
  1702. returned from an invocation, e.g.
  1703.  
  1704.   (classes$lookup("theClass"))$name()
  1705.  
  1706. These requirements are artifacts of the first implementation and are
  1707. subject to change.
  1708.  
  1709. The Idol preprocessor is written in Idol and does not actually parse
  1710. the language it purports to implement.  In particular, the
  1711. preprocessor is line-oriented and class and method declarations, the
  1712. initially keyword, and the class and method end keyword need to be on
  1713. a line by themselves.  Similarly, both the object being invoked and
  1714. its method and parameters must be on the same line for invocations.
  1715.  
  1716. The Idol preprocessor reserves certain names for internal use.  In
  1717. particular, __state and __methods are not legal class
  1718. field names.  Similarly, the name idol_object is reserved in the
  1719. global name space, and may not be used as a global variable, procedure,
  1720. or record name. Finally, for each class foo amongst the user's
  1721. code, the names foo, foo___state, foo___methods,
  1722. foo__oprec are reserved, as are the names foo__bar
  1723. corresponding to each method bar in class foo. These
  1724. details are artifacts of the current implementation and are subject
  1725. to change.
  1726.  
  1727. Subclass constructors can be confusing, especially when multiple
  1728. inheritance brings in various fields from different superclasses.
  1729. One significant problem for users of the subclass is that the
  1730. parameters expected in the constructor may not be obvious if they
  1731. are inherited from a superclass.  On the other side of the spectrum,
  1732. superclasses which automatically initialize their fields can be
  1733. less than useful if the subclass might need to override the
  1734. default initialization value--the subclass must then explicitly
  1735. name the field in order to make its initially section have
  1736. precedence over the superclass.
  1737.  
  1738. The first of the two problems given above can be solved by naming
  1739. fields explicitly in a subclass when initialization by constructor.
  1740. This achieves clarity at the expense of changing the inheritance
  1741. behavior, since the subclass no longer inherits the superclass
  1742. automatic initialization for that field if there is one.  The latter
  1743. of the two problems can generally be solved by using the / operator
  1744. in automatic field initializations unless the initialization should
  1745. never be overridden.
  1746.  
  1747. While it is occasionally convenient to redeclare an inherited field
  1748. in a subclass, accidentally doing so and then using that field to store an
  1749. unrelated value would be disastrous.  Although Idol offers no proper
  1750. solution to this problem, the -strict option causes the generation
  1751. of warning messages for each redefined field name noting the relevant
  1752. sub- and superclasses.
  1753.  
  1754.  
  1755.  
  1756.                              Running Idol
  1757.  
  1758. Idol requires Version 7.5 or higher of Icon.  It runs best on UNIX
  1759. systems.  It has not been ported to all the various micros and
  1760. operating systems on which Icon 7.5 runs.  In particular, if your
  1761. version of Icon does not support the system() function, or your
  1762. machine does not have adequate memory available, Idol will not be
  1763. able to invoke icont to complete its translation and linking.
  1764. Since Idol is untested on many systems, you may have to make small
  1765. changes to the source code in order to port it to a new system.
  1766.  
  1767.                             Getting a Copy
  1768.  
  1769. Idol is in the public domain.  It is available on the Icon BBS and by
  1770. anonymous ftp from cs.arizona.edu.  Idol is also distributed with
  1771. the program library for Version 8 of Icon and is available by mail in
  1772. this way.  Interested parties may contact the author
  1773. (cjeffery@cs.arizona.edu):
  1774.  
  1775.  
  1776.          Department of Computer Science
  1777.          University of Arizona
  1778.          Tucson, AZ 85721
  1779.  
  1780.  
  1781.                      Creating an Idol executable
  1782.  
  1783. Idol is typically distributed in both Idol and Icon source forms.
  1784. Creating an Idol executable requires a running version of Icon and a
  1785. copy of idolboot.icn, the Icon source for Idol.  A second Icon
  1786. source file contains the operating-system dependent portion of Idol;
  1787. for example, unix.icn (see the Idol README file for the name of
  1788. your system file if you are not on a UNIX system; you may have to
  1789. write your own, but it is not difficult).  Using icont, compile
  1790. idolboot.icn and unix.icn into an executable file (named
  1791. idolboot, or  idolboot.icx). As a final step, rename this
  1792. executable to idol (or idol.icx).
  1793.  
  1794.  
  1795.                 Installing the Idol Library Mechanism
  1796.  
  1797. For each directory in which Idol source is kept, the Idol preprocessor
  1798. normally uses a subdirectory to store its generated code on systems
  1799. which support a hierarchical file system.  On systems without a
  1800. hierarchy, it stores generated code in the source directory.  Before
  1801. actually running Idol on any source files you should install the
  1802. Idol libraries.  This is done by invoking the command
  1803.  
  1804. idol -install
  1805.  
  1806. (some systems use "iconx idol -install").  Follow any
  1807. directions given at this point; on most systems installation is
  1808. entirely automatic.
  1809.  
  1810.  
  1811.                       Translating Idol Programs
  1812.  
  1813. The syntax for invoking idol is normally
  1814.  
  1815. idol file1[.iol] [files...]
  1816.  
  1817. (on some systems you may have to say "iconx idol" where it
  1818. says "idol" above).  The Idol translator creates a separate
  1819. Icon file for each class in the Idol source files you give it.  On
  1820. most systems it calls icont automatically to create ucode for these
  1821. files.  If the first file on the command line has any normal Icon code
  1822. in it (in addition to any class definitions it may contain), Idol
  1823. attempts to link it to any classes it may need and create an executable.
  1824.  
  1825. The file extension defaults to .iol.  Idol also accepts
  1826. extensions .icn, .u1, and .cl.  The first two refer
  1827. to Icon source or already translated code for which Idol generates
  1828. link statements in the main (initial) Idol source file.  Idol treats
  1829. arguments with the extension .cl as class names and generates
  1830. link statements for that class and its superclasses.
  1831.  
  1832.                               References
  1833.  
  1834.  
  1835.  
  1836. [Gris83]
  1837. Griswold, R.E. and Griswold, M.T.
  1838. The Icon Programming Language.
  1839. Prentice-Hall, Englewood Cliffs, New Jersey, 1983.
  1840.  
  1841. [Gris87]
  1842. Griswold, R.E.
  1843. Programming in Icon; Part I---Programming with
  1844.   Co-Expressions.
  1845. Technical Report 87-6, Department of Computer Science, University of
  1846.   Arizona, June 1987.
  1847.  
  1848. [Walk86]
  1849. Walker, K.
  1850. Dynamic Environments---A Generalization of Icon String
  1851.   Scanning.
  1852. Technical Report 86-7, Department of Computer Science, University of
  1853.   Arizona, March 1986.
  1854.  
  1855.  
  1856. ##########
  1857. idol.iol
  1858. # @(#)idol.iol    6.30 (3/14/90)
  1859. #
  1860. # Idol: Icon-derived object language, version 6.30
  1861. #
  1862. # SYNOPSIS:
  1863. #
  1864. #   idol -install
  1865. #   idol prog[.iol] ... [-x args ]
  1866. #   prog
  1867. #
  1868. # FILES:
  1869. #
  1870. #   ./prog.iol                       : source file
  1871. #   ./prog.icn                     : Icon code for non-classes in prog.iol
  1872. #   ./idolcode.env/i_object.*      : Icon code for the universal object type
  1873. #   ./idolcode.env/classname.icn   : Icon files are generated for each class
  1874. #   ./idolcode.env/classname.u[12] : translated class files
  1875. #   ./idolcode.env/classname       : class specification/interface
  1876. #
  1877. # SEE ALSO:
  1878. #
  1879. #   "Programming in Idol: An Object Primer"
  1880. #   (U of Arizona Dept of CS Technical Report #90-10)
  1881. #   serves as user's guide and reference manual for Idol
  1882. #
  1883. ### Global variables
  1884. #
  1885. # FILES  : fin = input (.iol) file, fout = output (.icn) file
  1886. # CSETS  : alpha = identifier characters, nonalpha = everything else
  1887. #          alphadot = identifiers + '.'
  1888. #          white = whitespace, nonwhite = everything else
  1889. # TAQUES : classes in this module
  1890. # FLAGS  : comp if we should try to make an executable from args[1]
  1891. #          strict if we should generate paranoic encapsulation protection
  1892. #          loud if Idol should generate extra console messages
  1893. #          exec if we should run the result after translation
  1894. # LISTS  : links = names of external icon code to link to
  1895. #          imports = names of external classes to import
  1896. #          compiles = names of classes which need to be compiled
  1897. #
  1898. global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha
  1899. global classes,comp,exec,strict,links,imports,loud,compiles
  1900.  
  1901. #
  1902. # initialize global variables
  1903. #
  1904. procedure initialize()
  1905.   loud     := 1
  1906.   comp     := 0
  1907.   alpha    := &ucase ++ &lcase ++ '_' ++ &digits
  1908.   nonalpha := &cset -- alpha
  1909.   alphadot := alpha ++ '.'
  1910.   white    := ' \t\014'
  1911.   nonwhite := &cset -- white
  1912.   classes  := taque()
  1913.   links    := []
  1914.   imports  := []
  1915.   compiles := []
  1916.   sysinitialize()
  1917. end
  1918.  
  1919. procedure main(args)
  1920.     initialize()
  1921.     if *args = 0 then write("usage: idol files...")
  1922.     else {
  1923.       every i := 1 to *args do {
  1924.     if \exec then next            # after -x, args are for execution
  1925.     if args[i][1] == "-" then {
  1926.       case map(args[i]) of {
  1927.         "-c"   : {
  1928.         sysok := &null
  1929.         if comp = 0 then comp := -1        # don't make exe
  1930.         }
  1931.         "-install": return install(args[1:i+1])
  1932.         "-quiet"  : loud := &null
  1933.         "-strict" : strict := 1
  1934.         "-s"      : sysok := &null
  1935.         "-t"      : comp := -2                      # don't translate
  1936.         "-version": return write("Idol version 6.30 of 3/14/90") & 0
  1937.         "-x"      : exec := i
  1938.       }
  1939.         }
  1940.         else if args[i][find(".cl",args[i]):0] := "" then push(imports,args[i])
  1941.     else if args[i][find(".icn",args[i]):0] := "" then {
  1942.       push(links,args[i])
  1943.       icont(" -c "||args[i])
  1944.     }
  1945.     else if args[i][find(".u1",args[i]):0] := "" then push(links,args[i])
  1946.     else if (args[i][find(".iol",args[i]):0] := "") |
  1947.         tryopen(args[i]||".iol","r") then {
  1948.       /exe := i
  1949.       args[i][find(".iol",args[i]):0] := ""
  1950.       /fout := sysopen(args[i]||".icn","w")
  1951.       readinput(args[i]||".iol",1)
  1952.         } else {
  1953.           #
  1954.           # let's go out and look for an appropriate .icn, .u1 or class file!
  1955.           #
  1956.       if tryopen(args[i]||".icn","r") then {
  1957.         push(links,args[i])
  1958.         icont(" -c "||args[i])
  1959.       }
  1960.       else if tryopen(args[i]||".u1") then push(links,args[i])
  1961.       else if tryenvopen(args[i]) then push(imports,args[i])
  1962.     }
  1963.       }
  1964.       gencode()
  1965.       close(\fout)
  1966.       if comp = 1 then makeexe(args,exe)
  1967.     }
  1968. end
  1969.  
  1970. #
  1971. # gencode first generates specifications for all defined classes
  1972. # It then imports those classes' specifications which it needs to
  1973. # compute inheritance.  Finally, it writes out all classes' .icn files.
  1974. #
  1975. procedure gencode()
  1976.   if \loud then write("Class import/export:")
  1977.   #
  1978.   # export specifications for each class
  1979.   #
  1980.   every cl := classes$foreach_t() do cl$writespec()
  1981.   #
  1982.   # import class specifications, transitively
  1983.   #
  1984.   repeat {
  1985.     added := 0
  1986.     every super:= ((classes$foreach_t())$foreachsuper() | !imports) do{
  1987.       if /classes$lookup(super) then {
  1988.     added := 1
  1989.     fname := filename(super)
  1990.     readinput(envpath(fname),2)
  1991.     if /classes$lookup(super) then halt("can't import class '",super,"'")
  1992.     writesublink(fname)
  1993.       }
  1994.     }
  1995.     if added = 0 then break
  1996.   }
  1997.   #
  1998.   # compute the transitive closure of the superclass graph
  1999.   #
  2000.   every (classes$foreach_t())$transitive_closure()
  2001.   #
  2002.   # generate output
  2003.   #
  2004.   if \loud then write("Generating code:")
  2005.   writesublink("i_object")
  2006.   every s := !links do writelink(s)
  2007.   write(fout)
  2008.   every out := $!classes do {
  2009.     name := filename(out$name())
  2010.     out$write()
  2011.     put(compiles,name)
  2012.     writesublink(name)
  2013.   }
  2014.   if *compiles>0 then cdicont(compiles)
  2015. end
  2016.  
  2017. #
  2018. # a class defining objects resulting from parsing lines of the form
  2019. # tag name ( field1 , field2, ... )
  2020. # If the constructor is given an argument, it is passed to self$read
  2021. #
  2022. class declaration(public name,fields,tag)
  2023.   #
  2024.   # parse a declaration string into its components
  2025.   #
  2026.   method read(decl)
  2027.     decl ? {
  2028.       # get my tag
  2029.       tab(many(white))
  2030.       if not (self.tag := =("procedure"|"class"|"method"|"record")) then
  2031.     halt("declaration/read can't parse decl ",decl)
  2032.       tab(many(white))
  2033.       # get my name
  2034.       if not (self.name := tab(many(alpha))) then
  2035.     halt("declaration/read can't parse decl ",decl)
  2036.       # get my fields
  2037.       if not tab(find("(")+1) then
  2038.       halt("declaration/read can't parse decl ",decl)
  2039.       tab(many(white))
  2040.       self.fields := classFields()
  2041.       if not (self.fields$parse(tab(find(")")))) then
  2042.     halt("declaration/read can't parse decl ",decl)
  2043.     }
  2044.   end
  2045.  
  2046.   #
  2047.   # write a declaration; at the moment, only used by records
  2048.   #
  2049.   method write(f)
  2050.      write(f,self$String())
  2051.   end
  2052.   #
  2053.   # convert self to a string
  2054.   #
  2055.   method String()
  2056.     return self.tag || " " || self.name || "(" || self.fields$String() || ")"
  2057.   end
  2058. initially
  2059.   if \self.name then self$read(self.name)
  2060. end
  2061.  
  2062. #
  2063. # class body manages a list of strings holding the code for
  2064. # procedures/methods/classes
  2065. #
  2066. class body(fn,ln,text)
  2067.   method read()
  2068.     self.fn    := fName
  2069.     self.ln    := fLine
  2070.     self.text  := []
  2071.     while line := readln() do {
  2072.       put(self.text, line)
  2073.       line ? { tab(many(white)); if ="end" & &pos > *line then return }
  2074.     }
  2075.     halt("body/read: eof inside a procedure/method definition")
  2076.   end
  2077.   method write(f)
  2078.     if \self.ln then write(f,"#line ",self.ln," \"",self.fn,"\"")
  2079.     every write(f,$!self)
  2080.   end
  2081.   method delete()
  2082.     return pull(self.text)
  2083.   end
  2084.   method size()
  2085.     return (*\ (self.text)) | 0
  2086.   end
  2087.   method foreach()
  2088.     if t := \self.text then suspend !self.text
  2089.   end
  2090. end
  2091.  
  2092. #
  2093. # a class defining operations on classes
  2094. #
  2095. class class : declaration (supers,methods,text,imethods,ifields,glob)
  2096.   # imethods and ifields are all lists of these:
  2097.   record classident(class,ident)
  2098.  
  2099.   method read(line,phase)
  2100.     self$declaration.read(line)
  2101.     self.supers := idTaque(":")
  2102.     self.supers$parse(line[find(":",line)+1:find("(",line)] | "")
  2103.     self.methods:= taque()
  2104.     self.text   := body()
  2105.     while line  := readln() do {
  2106.       line ? {
  2107.     tab(many(white))
  2108.     if ="initially" then {
  2109.         self.text$read()
  2110.         if phase=2 then return
  2111.         self.text$delete()    # "end" appended manually during writing after
  2112.                 # generation of the appropriate return value
  2113.         return
  2114.     } else if ="method" then {
  2115.         decl := method(self.name)
  2116.         decl$read(line,phase)
  2117.         self.methods$insert(decl,decl$name())
  2118.     } else if ="end" then {
  2119.         # "end" is tossed here. see "initially" above
  2120.         return
  2121.     } else if ="procedure" then {
  2122.         decl := Procedure("")
  2123.         decl$read(line,phase)
  2124.         /self.glob := []
  2125.         put(self.glob,decl)
  2126.     } else if ="global" then {
  2127.         /self.glob := []
  2128.         put(self.glob,Global(line))
  2129.     } else if ="record" then {
  2130.         /self.glob := []
  2131.         put(self.glob,declaration(line))
  2132.     } else if upto(nonwhite) then {
  2133.         halt("class/read expected declaration on: ",line)
  2134.     }
  2135.       }
  2136.     }
  2137.     halt("class/read syntax error: eof inside a class definition")
  2138.   end
  2139.  
  2140.   #
  2141.   # Miscellaneous methods on classes
  2142.   #
  2143.   method has_initially()
  2144.     return $*self.text > 0
  2145.   end
  2146.   method ispublic(fieldname)
  2147.     if self.fields$ispublic(fieldname) then return fieldname
  2148.   end
  2149.   method foreachmethod()
  2150.     suspend $!self.methods
  2151.   end
  2152.   method foreachsuper()
  2153.     suspend $!self.supers
  2154.   end
  2155.   method foreachfield()
  2156.     suspend $!self.fields
  2157.   end
  2158.   method transitive_closure()
  2159.     count := $*self.supers
  2160.     while count > 0 do {
  2161.     added := taque()
  2162.     every sc := $!self.supers do {
  2163.       if /(super := classes$lookup(sc)) then
  2164.         halt("class/transitive_closure: couldn't find superclass ",sc)
  2165.       every supersuper := super$foreachsuper() do {
  2166.         if / self.supers$lookup(supersuper) &
  2167.          /added$lookup(supersuper) then {
  2168.           added$insert(supersuper)
  2169.         }
  2170.       }
  2171.     }
  2172.     count := $*added
  2173.     every self.supers$insert($!added)
  2174.     }
  2175.   end
  2176.   #
  2177.   # write the class declaration: if s is "class" write as a spec
  2178.   # otherwise, write as a constructor
  2179.   #
  2180.   method writedecl(f,s)
  2181.     writes(f, s," ",self.name)
  2182.     if s=="class" & ( *(supers := self.supers$String()) > 0 ) then
  2183.         writes(f," : ",supers)
  2184.     writes(f,"(")
  2185.     rv := self.fields$String(s)
  2186.     if *rv > 0 then rv ||:= ","
  2187.     if s~=="class" & \self.ifields then        # inherited fields
  2188.       every l := !self.ifields do rv ||:= l.ident || ","
  2189.     writes(f,rv[1:-1])
  2190.     write(f,,")")
  2191.   end
  2192.   method writespec(f) # write the specification of a class
  2193.     f := envopen(filename(self.name),"w")
  2194.     self$writedecl(f,"class")
  2195.     every ($!self.methods)$writedecl(f,"method")
  2196.     if self$has_initially() then write(f,"initially")
  2197.     write(f,"end")
  2198.     close(f)
  2199.   end
  2200.  
  2201.   #
  2202.   # write out the Icon code for this class' explicit methods
  2203.   # and its "nested global" declarations (procedures, records, etc.)
  2204.   #
  2205.   method writemethods()
  2206.     f:= envopen(filename(self.name)||".icn","w")
  2207.     every ($!self.methods)$write(f,self.name)
  2208.  
  2209.     if \self.glob & *self.glob>0 then {
  2210.     write(f,"#\n# globals declared within the class\n#")
  2211.     every i := 1 to *self.glob do (self.glob[i])$write(f,"")
  2212.     }
  2213.     close(f)
  2214.   end
  2215.  
  2216.   #
  2217.   # write - write an Icon implementation of a class to file f
  2218.   #
  2219.   method write()
  2220.     f:= envopen(filename(self.name)||".icn","a")
  2221.     #
  2222.     # must have done inheritance computation to write things out
  2223.     #
  2224.     if /self.ifields then self$resolve()
  2225.  
  2226.     #
  2227.     # write a record containing the state variables
  2228.     #
  2229.     writes(f,"record ",self.name,"_state(__state,__methods") # reserved fields
  2230.     rv := ","
  2231.     rv ||:= self.fields$idTaque.String()             # my fields
  2232.     if rv[-1] ~== "," then rv ||:= ","
  2233.     every s := (!self.ifields).ident do rv ||:= s || "," # inherited fields
  2234.     write(f,rv[1:-1],")")
  2235.  
  2236.     #
  2237.     # write a record containing the methods
  2238.     #
  2239.     writes(f,"record ",self.name,"_methods(")
  2240.     rv := ""
  2241.  
  2242.     every s := ((($!self.methods)$name())    |    # my explicit methods
  2243.         self.fields$foreachpublic()    |    # my implicit methods
  2244.         (!self.imethods).ident        |    # my inherited methods
  2245.         $!self.supers)                # super.method fields
  2246.     do rv ||:= s || ","
  2247.  
  2248.     if *rv>0 then rv[-1] := ""            # trim trailling ,
  2249.     write(f,rv,")")
  2250.  
  2251.     #
  2252.     # write a global containing this classes' operation record
  2253.     # along with declarations for all superclasses op records
  2254.     #
  2255.     writes(f,"global ",self.name,"__oprec")
  2256.     every writes(f,", ", $!self.supers,"__oprec")
  2257.     write(f)
  2258.  
  2259.     #
  2260.     # write the constructor procedure.
  2261.     # This is a long involved process starting with writing the declaration.
  2262.     #
  2263.     self$writedecl(f,"procedure")
  2264.     write(f,"local self,clone")
  2265.  
  2266.     #
  2267.     # initialize operation records for this and superclasses
  2268.     #
  2269.     write(f,"initial {\n",
  2270.         "  if /",self.name,"__oprec then ",self.name,"initialize()")
  2271.     if $*self.supers > 0 then
  2272.     every (super <- $!self.supers) ~== self.name do
  2273.         write(f,"  if /",super,"__oprec then ",super,"initialize()\n",
  2274.             "  ",self.name,"__oprec.",super," := ", super,"__oprec")
  2275.     write(f,"  }")
  2276.  
  2277.     #
  2278.     # create self, initialize from constructor parameters
  2279.     #
  2280.     writes(f,"  self := ",self.name,"_state(&null,",self.name,"__oprec")
  2281.     every writes(f,",",$!self.fields)
  2282.     if \self.ifields then every writes(f,",",(!self.ifields).ident)
  2283.     write(f,")\n  self.__state := self")
  2284.  
  2285.     #
  2286.     # call my own initially section, if any
  2287.     #
  2288.     if $*self.text > 0 then write(f,"  ",self.name,"initially(self)")
  2289.  
  2290.     #
  2291.     # call superclasses' initially sections
  2292.     #
  2293.     if $*self.supers > 0 then {
  2294.     every (super <- $!self.supers) ~== self.name do {
  2295.         if (classes$lookup(super))$has_initially() then {
  2296.         if /madeclone := 1 then {
  2297.             write(f,"  clone := ",self.name,"_state()\n",
  2298.             "  clone.__state := clone\n",
  2299.             "  clone.__methods := ",self.name,"__oprec")
  2300.         }
  2301.         write(f,"  # inherited initialization from class ",super)
  2302.         write(f,"    every i := 2 to *self do clone[i] := self[i]\n",
  2303.             "    ",super,"initially(clone)")
  2304.         every l := !self.ifields do {
  2305.             if l.class == super then
  2306.             write(f,"    self.",l.ident," := clone.",l.ident)
  2307.         }
  2308.         }
  2309.     }
  2310.     }
  2311.  
  2312.     #
  2313.     # return the pair that comprises the object:
  2314.     # a pointer to the instance (__mystate), and
  2315.     # a pointer to the class operation record
  2316.     #
  2317.     write(f,"  return idol_object(self,",self.name,"__oprec)\n",
  2318.         "end\n")
  2319.     
  2320.     #
  2321.     # write out class initializer procedure to initialize my operation record
  2322.     #
  2323.     write(f,"procedure ",self.name,"initialize()")
  2324.     writes(f,"  initial ",self.name,"__oprec := ",self.name,"_methods")
  2325.     rv := "("
  2326.     every s := ($!self.methods)$name() do {        # explicit methods
  2327.       if *rv>1 then rv ||:= ","
  2328.       rv ||:= self.name||s
  2329.     }
  2330.     every me := self.fields$foreachpublic() do {    # implicit methods
  2331.       if *rv>1 then rv ||:= ","            # (for public fields)
  2332.       rv ||:= self.name||me
  2333.     }
  2334.     every l := !self.imethods do {            # inherited methods
  2335.       if *rv>1 then rv ||:= ","
  2336.       rv ||:= l.class||l.ident
  2337.     }
  2338.     write(f,rv,")\n","end")
  2339.     #
  2340.     # write out initially procedure, if any
  2341.     #
  2342.     if self$has_initially() then {
  2343.     write(f,"procedure ",self.name,"initially(self)")
  2344.     self.text$write(f)
  2345.     write(f,"end")
  2346.     }
  2347.  
  2348.     #
  2349.     # write out implicit methods for public fields
  2350.     #
  2351.     every me := self.fields$foreachpublic() do {
  2352.       write(f,"procedure ",self.name,me,"(self)")
  2353.       if \strict then {
  2354.     write(f,"  if type(self.",me,") == ",
  2355.         "(\"list\"|\"table\"|\"set\"|\"record\") then\n",
  2356.         "    runerr(501,\"idol: scalar type expected\")")
  2357.     }
  2358.       write(f,"  return .(self.",me,")")
  2359.       write(f,"end")
  2360.       write(f)
  2361.     }
  2362.  
  2363.     close(f)
  2364.  
  2365.   end
  2366.  
  2367.   #
  2368.   # resolve -- primary inheritance resolution utility
  2369.   #
  2370.   method resolve()
  2371.     #
  2372.     # these are lists of [class , ident] records
  2373.     #
  2374.     self.imethods := []
  2375.     self.ifields := []
  2376.     ipublics := []
  2377.     addedfields := table()
  2378.     addedmethods := table()
  2379.     every sc := $!self.supers do {
  2380.     if /(superclass := classes$lookup(sc)) then
  2381.         halt("class/resolve: couldn't find superclass ",sc)
  2382.     every superclassfield := superclass$foreachfield() do {
  2383.         if /self.fields$lookup(superclassfield) &
  2384.            /addedfields[superclassfield] then {
  2385.         addedfields[superclassfield] := superclassfield
  2386.         put ( self.ifields , classident(sc,superclassfield) )
  2387.         if superclass$ispublic(superclassfield) then
  2388.             put( ipublics, classident(sc,superclassfield) )
  2389.         } else if \strict then {
  2390.         warn("class/resolve: '",sc,"' field '",superclassfield,
  2391.              "' is redeclared in subclass ",self.name)
  2392.         }
  2393.     }
  2394.     every superclassmethod := (superclass$foreachmethod())$name() do {
  2395.         if /self.methods$lookup(superclassmethod) &
  2396.            /addedmethods[superclassmethod] then {
  2397.         addedmethods[superclassmethod] := superclassmethod
  2398.         put ( self.imethods, classident(sc,superclassmethod) )
  2399.         }
  2400.     }
  2401.     every public := (!ipublics) do {
  2402.         if public.class == sc then
  2403.         put (self.imethods, classident(sc,public.ident))
  2404.     }
  2405.     }
  2406.   end
  2407. end
  2408.  
  2409. #
  2410. # a class defining operations on methods and procedures
  2411. #
  2412. class method : declaration (class,text)
  2413.   method read(line,phase)
  2414.     self$declaration.read(line)
  2415.     self.text := body()
  2416.     if phase = 1 then
  2417.       self.text$read()
  2418.   end
  2419.   method writedecl(f,s)
  2420.     decl := self$String()
  2421.     if s == "method" then decl[1:upto(white,decl)] := "method"
  2422.     else {
  2423.     decl[1:upto(white,decl)] := "procedure"
  2424.     decl[upto(white,decl)] ||:= self.class
  2425.     if *self.class ~= 0 then {
  2426.         i := find("(",decl)
  2427.         decl[i] ||:= "self" || (((decl[i+1] ~== ")"), ",") | "")
  2428.     }
  2429.     }
  2430.     write(f,decl)
  2431.   end
  2432.   method write(f)
  2433.     if self.name ~== "initially" then
  2434.     self$writedecl(f,"procedure")
  2435.     self.text$write(f)
  2436.     self.text := &null            # after writing out text, forget it!
  2437.   end
  2438. end
  2439.  
  2440. #
  2441. # A class for ordinary Icon global declarations
  2442. #
  2443. class Global(s)
  2444.   method write(f)
  2445.     write(f,self.s)
  2446.   end
  2447. end
  2448.  
  2449. #
  2450. # a class corresponding to an Icon table, with special treatment of empties
  2451. #
  2452. class Table(t)
  2453.   method size()
  2454.     return (* \ self.t) | 0
  2455.   end
  2456.   method insert(x,key)
  2457.     /self.t := table()
  2458.     /key := x
  2459.     if / (self.t[key]) := x then return
  2460.   end
  2461.   method lookup(key)
  2462.     if t := \self.t then return t[key]
  2463.     return
  2464.   end
  2465.   method foreach()
  2466.     if t := \self.t then every suspend !self.t
  2467.   end
  2468. end
  2469.  
  2470. #
  2471. # tabular queues (taques):
  2472. # a class defining objects which maintain synchronized list and table reps
  2473. # Well, what is really provided are loosely-coordinated list/tables
  2474. #
  2475. class taque : Table (l)
  2476.   method insert(x,key)
  2477.     /self.l := []
  2478.     if self$Table.insert(x,key) then put(self.l,x)
  2479.   end
  2480.   method foreach()
  2481.     if l := \self.l then every suspend !self.l
  2482.   end
  2483.   method insert_t(x,key)
  2484.     self$Table.insert(x,key)
  2485.   end
  2486.   method foreach_t()
  2487.     suspend self$Table.foreach()
  2488.   end
  2489. end
  2490.  
  2491. #
  2492. # support for taques found as lists of ids separated by punctuation
  2493. # constructor called with (separation char, source string)
  2494. #
  2495. class idTaque : taque(punc)
  2496.   method parse(s)
  2497.     s ? {
  2498.       tab(many(white))
  2499.       while name := tab(find(self.punc)) do {
  2500.     self$insert(trim(name))
  2501.     move(1)
  2502.     tab(many(white))
  2503.       }
  2504.       if any(nonwhite) then self$insert(trim(tab(0)))
  2505.     }
  2506.     return
  2507.   end
  2508.   method String()
  2509.     if /self.l then return ""
  2510.     out := ""
  2511.     every id := !self.l do out ||:= id||self.punc
  2512.     return out[1:-1]
  2513.   end
  2514. end
  2515.  
  2516. #
  2517. # parameter lists in which the final argument may have a trailing []
  2518. #
  2519. class argList : idTaque(public varg)
  2520.   method insert(s)
  2521.     if \self.varg then halt("variable arg must be final")
  2522.     if i := find("[",s) then {
  2523.       if not (j := find("]",s)) then halt("variable arg expected ]")
  2524.       s[i : j+1] := ""
  2525.       self.varg := s := trim(s)
  2526.     }
  2527.     self$idTaque.insert(s)
  2528.   end
  2529.   method String()
  2530.     return self$idTaque.String() || ((\self.varg & "[]") | "")
  2531.   end
  2532. initially
  2533.   self.punc := ","
  2534. end
  2535.  
  2536. #
  2537. # Idol class field lists in which fields may be preceded by a "public" keyword
  2538. #
  2539. class classFields : argList(publics)
  2540.   method String(s)
  2541.     if *(rv := self$argList.String()) = 0 then return ""
  2542.     if /s | (s ~== "class") then return rv
  2543.     if self$ispublic(self.l[1]) then rv := "public "||rv
  2544.     every field:=self$foreachpublic() do rv[find(","||field,rv)] ||:= "public "
  2545.     return rv
  2546.   end
  2547.   method foreachpublic()
  2548.     if \self.publics then every suspend !self.publics
  2549.   end
  2550.   method ispublic(s)
  2551.     if \self.publics then every suspend !self.publics == s
  2552.   end
  2553.   method insert(s)
  2554.     s ? {
  2555.       if ="public" & tab(many(white)) then {
  2556.     s := tab(0)
  2557.     /self.publics := []
  2558.     put(self.publics,s)
  2559.       }
  2560.     }
  2561.     self$argList.insert(s)
  2562.   end
  2563. initially
  2564.   self.punc := ","
  2565. end
  2566.  
  2567. #
  2568. # tell whether the character following s is within a quote or not
  2569. #
  2570. procedure notquote(s)
  2571.   quotes := 0
  2572.   outs := ""
  2573.   # this is a bug for people who write code like \"hello"...
  2574.   s ? {
  2575.     while outs ||:= tab(find("\\")+1) do { move(1) }
  2576.     outs ||:= tab(0)
  2577.   }
  2578.   s := outs
  2579.   outs := ""
  2580.   s ? {
  2581.     while outs ||:= tab(find("\""|"'")+1) do {
  2582.     quotes +:= 1
  2583.     if tab(find(outs[-1])) then {
  2584.         quotes +:= 1
  2585.         move(1)
  2586.     }
  2587.     }
  2588.   }
  2589.   if quotes % 2 = 0 then return
  2590. end
  2591.  
  2592. #
  2593. # filter the input translating $ references
  2594. # (also eats comments and trims lines)
  2595. #
  2596. procedure readln()
  2597.     count := 0
  2598.     if line := read(fin) then {
  2599.     fLine +:= 1
  2600.     line[ 1(x<-find("#",line),notquote(line[1:x])) : 0] := ""
  2601.     line := trim(line)
  2602.     while ((x := find("$",line)) & notquote(line[1:x])) do {
  2603.         z := line[x+1:0] ||" "         # " " is for bal()
  2604.         if find(line[x+1],"!*@?") then { # Invocation operators $! $* $@ $?
  2605.         z ? {
  2606.             move(1)
  2607.             tab(many(white))
  2608.             if not (id := tab(many(alphadot))) then {
  2609.               if not match("(") then halt("readline can't parse ",line)
  2610.               if not (id := tab(&pos<bal())) then
  2611.               halt("readline: cant bal ",&subject)
  2612.             }
  2613.             case line[x+1] of {
  2614.             "@": Op := "activate"
  2615.             "*": Op := "size"
  2616.             "!": Op := "foreach"
  2617.             "?": Op := "random"
  2618.             default: halt("readline: unknown operator $",line[x+1])
  2619.             }
  2620.             count +:= 1
  2621.             line[x:0] :=
  2622.             "(__self"||count||" := "||id||").__methods."||
  2623.             Op||"(__self"||count||".__state)"||tab(0)
  2624.         }
  2625.         } else {
  2626.         reverse(line[1:x])||" " ? {
  2627.             tab(many(white))
  2628.             if not (id := reverse(tab(many(alphadot)))) then {
  2629.               if not match(")") then halt("readline: can't parse")
  2630.               if not (id := reverse(tab(&pos<bal(&cset,')','('))))
  2631.             then halt("readline: can't bal ",&subject)
  2632.             }
  2633.             nummatched := &pos-1
  2634.         }
  2635.         if not (lp := find("(",z)) then halt("readline: expected '('")
  2636.         if z[lp+1] ~== ")" then c:="," else c:=""
  2637.         count +:= 1
  2638.         line[x-nummatched : x+lp+1] :=
  2639.           "(__self"||count||" := "||id||").__methods."||
  2640.             z[1:lp+1]||"__self"||count||".__state"||c
  2641.         }
  2642.     }
  2643.     return line
  2644.  
  2645.  
  2646.     } else fail
  2647. end
  2648.  
  2649. #
  2650. # procedure to read a single Idol source file
  2651. #
  2652. procedure readinput(name,phase)
  2653.     if \loud then write("\t",name)
  2654.     fName := name
  2655.     fLine := 0
  2656.     fin   := sysopen(name,"r")
  2657.     while line := readln() do {
  2658.     line ? {
  2659.         tab(many(white))
  2660.         if ="class" then {
  2661.         decl := class()
  2662.         decl$read(line,phase)
  2663.         if phase=1 then {
  2664.             decl$writemethods()
  2665.             classes$insert(decl,decl$name())
  2666.         } else classes$insert_t(decl,decl$name())
  2667.         }
  2668.         else if ="procedure" then {
  2669.         if comp = 0 then comp := 1
  2670.         decl := method("")
  2671.         decl$read(line,phase)
  2672.         decl$write(fout,"")
  2673.         }
  2674.         else if ="record" then {
  2675.         if comp = 0 then comp := 1
  2676.         decl := declaration(line)
  2677.         decl$write(fout,"")
  2678.         }
  2679.         else if ="global" then {
  2680.         if comp = 0 then comp := 1
  2681.         decl := Global(line)
  2682.         decl$write(fout,"")
  2683.         }
  2684.         else if ="method" then {
  2685.         halt("readinput: method outside class")
  2686.         }
  2687.     }
  2688.     }
  2689.     close(fin)
  2690. end
  2691.  
  2692. #
  2693. # error/warning/message handling
  2694. #
  2695. procedure halt(args[])
  2696.   errsrc()
  2697.   every writes(&errout,!args)
  2698.   stop()
  2699. end
  2700.  
  2701. procedure warn(args[])
  2702.   errsrc()
  2703.   every writes(&errout,!args)
  2704.   write(&errout)
  2705. end
  2706.  
  2707. procedure errsrc()
  2708.   writes(&errout,"\"",\fName,"\", line ",\fLine,": Idol/")
  2709. end
  2710. #
  2711. # System-independent, but system related routines
  2712. #
  2713. procedure tryopen(file,mode)
  2714.   if f := open(file,mode) then return close(f)
  2715. end
  2716. procedure tryenvopen(file,mode)
  2717.   return tryopen(envpath(file),mode)
  2718. end
  2719. procedure sysopen(file,mode)
  2720.   if not (f := open(file,mode)) then
  2721.       halt("Couldn't open file ",file," for mode ",mode)
  2722.   return f
  2723. end
  2724. procedure envopen(file,mode)
  2725.   return sysopen(envpath(file),mode)
  2726. end
  2727. procedure writelink(s)
  2728.   write(fout,"link \"",s,"\"")
  2729. end
  2730. procedure icont(argstr,prefix)
  2731. static s
  2732. initial { s := (getenv("ICONT")|"icont") }
  2733.   return mysystem(\prefix||s||argstr | s||argstr)
  2734. end
  2735. ##########
  2736. idol.man
  2737. NAME
  2738.     idol - Icon-Derived Object Language
  2739.  
  2740. SYNOPSIS
  2741.     idol -install
  2742.     idol [ option ... ] mainfile otherfiles... [-x arguments]
  2743.  
  2744. DESCRIPTION
  2745.     Idol is an object-oriented preprocessor for Version 7.5+ Icon.
  2746.     It is a front-end for icont(1); typically one invokes idol on
  2747.     a source file (extension .iol) which is translated into an
  2748.     Icon source file (extension .icn) which is translated into a
  2749.     file suitable for interpretation by the Icon interpreter.
  2750.     Each directory containing Idol source files should be initialized
  2751.     by "idol -install" prior to translating any user sources.
  2752.     Producing an executable is skipped when the first file on the
  2753.     list contains only classes.
  2754.  
  2755.     The following options are recognized by idol:
  2756.  
  2757.     -c       Suppress the linking phase
  2758.     -t       Suppress all translation by icont
  2759.     -s       Suppress removal of .icn files after translation by icont
  2760.     -quiet   Suppress most Idol-specific console messages
  2761.     -install Install the Idol environment in the current directory
  2762.     -strict  Generate code which is paranoid about ensuring encapsulation
  2763.     -version Print out the version of Idol and its date of creation
  2764.  
  2765.     The second and following files on the command line may include
  2766.     extensions .icn, .u1, and .cl.  The first two Idol treats as
  2767.     Icon source code which should be translated and linked into the
  2768.     resulting executable.  Files with extension .cl are treated as
  2769.     class names which are linked into the resulting executable.
  2770.     If no extension is given, Idol attempts to find the desired
  2771.     source file by appending .iol, .icn, .u1, or .cl in that order.
  2772.  
  2773. FILES
  2774.  
  2775.    ./prog.iol                     : source file
  2776.    ./prog.icn                     : code generated for non-classes in prog.iol
  2777.    ./idolcode.env/i_object.*      : Icon code for the universal object type
  2778.    ./idolcode.env/classname.icn   : Icon files are generated for each class
  2779.    ./idolcode.env/classname.u[12] : translated class files
  2780.    ./idolcode.env/classname       : class specification/interface
  2781.  
  2782. SEE ALSO
  2783.  
  2784.    "Programming in Idol: An Object Primer"
  2785.    (U of Arizona Dept of CS Technical Report #90-10)
  2786.    serves as user's guide and reference manual for Idol
  2787. ##########
  2788. idolboot.icn
  2789. global fin,fout,fName,fLine,alpha,alphadot,white,nonwhite,nonalpha
  2790. global classes,comp,exec,strict,links,imports,loud,compiles
  2791. procedure initialize()
  2792. #line 47 "idol.iol"
  2793.   loud     := 1
  2794.   comp     := 0
  2795.   alpha    := &ucase ++ &lcase ++ '_' ++ &digits
  2796.   nonalpha := &cset -- alpha
  2797.   alphadot := alpha ++ '.'
  2798.   white    := ' \t\014'
  2799.   nonwhite := &cset -- white
  2800.   classes  := taque()
  2801.   links    := []
  2802.   imports  := []
  2803.   compiles := []
  2804.   sysinitialize()
  2805. end
  2806. procedure main(args)
  2807. #line 62 "idol.iol"
  2808.     initialize()
  2809.     if *args = 0 then write("usage: idol files...")
  2810.     else {
  2811.       every i := 1 to *args do {
  2812.     if \exec then next
  2813.     if args[i][1] == "-" then {
  2814.       case map(args[i]) of {
  2815.         "-c"   : {
  2816.         sysok := &null
  2817.         if comp = 0 then comp := -1
  2818.         }
  2819.         "-install": return install(args[1:i+1])
  2820.         "-quiet"  : loud := &null
  2821.         "-strict" : strict := 1
  2822.         "-s"      : sysok := &null
  2823.         "-t"      : comp := -2
  2824.         "-version": return write("Idol version 6.30 of 3/14/90") & 0
  2825.         "-x"      : exec := i
  2826.       }
  2827.         }
  2828.         else if args[i][find(".cl",args[i]):0] := "" then push(imports,args[i])
  2829.     else if args[i][find(".icn",args[i]):0] := "" then {
  2830.       push(links,args[i])
  2831.       icont(" -c "||args[i])
  2832.     }
  2833.     else if args[i][find(".u1",args[i]):0] := "" then push(links,args[i])
  2834.     else if (args[i][find(".iol",args[i]):0] := "") |
  2835.         tryopen(args[i]||".iol","r") then {
  2836.       /exe := i
  2837.       args[i][find(".iol",args[i]):0] := ""
  2838.       /fout := sysopen(args[i]||".icn","w")
  2839.       readinput(args[i]||".iol",1)
  2840.         } else {
  2841.  
  2842.  
  2843.  
  2844.       if tryopen(args[i]||".icn","r") then {
  2845.         push(links,args[i])
  2846.         icont(" -c "||args[i])
  2847.       }
  2848.       else if tryopen(args[i]||".u1") then push(links,args[i])
  2849.       else if tryenvopen(args[i]) then push(imports,args[i])
  2850.     }
  2851.       }
  2852.       gencode()
  2853.       close(\fout)
  2854.       if comp = 1 then makeexe(args,exe)
  2855.     }
  2856. end
  2857. procedure gencode()
  2858. #line 118 "idol.iol"
  2859.   if \loud then write("Class import/export:")
  2860.  
  2861.  
  2862.  
  2863.   every cl := (__self1 := classes).__methods.foreach_t(__self1.__state) do (__self2 := cl).__methods.writespec(__self2.__state)
  2864.  
  2865.  
  2866.  
  2867.   repeat {
  2868.     added := 0
  2869.     every super:= ((__self2 := ((__self1 := classes).__methods.foreach_t(__self1.__state))).__methods.foreachsuper(__self2.__state) | !imports) do{
  2870.       if /(__self1 := classes).__methods.lookup(__self1.__state,super) then {
  2871.     added := 1
  2872.     fname := filename(super)
  2873.     readinput(envpath(fname),2)
  2874.     if /(__self1 := classes).__methods.lookup(__self1.__state,super) then halt("can't import class '",super,"'")
  2875.     writesublink(fname)
  2876.       }
  2877.     }
  2878.     if added = 0 then break
  2879.   }
  2880.  
  2881.  
  2882.  
  2883.   every (__self2 := ((__self1 := classes).__methods.foreach_t(__self1.__state))).__methods.transitive_closure(__self2.__state)
  2884.  
  2885.  
  2886.  
  2887.   if \loud then write("Generating code:")
  2888.   writesublink("i_object")
  2889.   every s := !links do writelink(s)
  2890.   write(fout)
  2891.   every out := (__self1 := classes).__methods.foreach(__self1.__state) do { 
  2892.     name := filename((__self1 := out).__methods.name(__self1.__state))
  2893.     (__self1 := out).__methods.write(__self1.__state)
  2894.     put(compiles,name)
  2895.     writesublink(name)
  2896.   }
  2897.   if *compiles>0 then cdicont(compiles)
  2898. end
  2899. procedure notquote(s)
  2900. #line 713 "idol.iol"
  2901.   quotes := 0
  2902.   outs := ""
  2903.  
  2904.   s ? {
  2905.     while outs ||:= tab(find("\\")+1) do { move(1) }
  2906.     outs ||:= tab(0)
  2907.   }
  2908.   s := outs
  2909.   outs := ""
  2910.   s ? {
  2911.     while outs ||:= tab(find("\""|"'")+1) do {
  2912.     quotes +:= 1
  2913.     if tab(find(outs[-1])) then {
  2914.         quotes +:= 1
  2915.         move(1)
  2916.     }
  2917.     }
  2918.   }
  2919.   if quotes % 2 = 0 then return
  2920. end
  2921. procedure readln()
  2922. #line 739 "idol.iol"
  2923.     count := 0
  2924.     if line := read(fin) then {
  2925.     fLine +:= 1
  2926.     line[ 1(x<-find("#",line),notquote(line[1:x])) : 0] := ""
  2927.     line := trim(line)
  2928.     while ((x := find("$",line)) & notquote(line[1:x])) do {
  2929.         z := line[x+1:0] ||" "    
  2930.         if find(line[x+1],"!*@?") then {
  2931.         z ? {
  2932.             move(1)
  2933.             tab(many(white))
  2934.             if not (id := tab(many(alphadot))) then {
  2935.               if not match("(") then halt("readline can't parse ",line)
  2936.               if not (id := tab(&pos<bal())) then
  2937.               halt("readline: cant bal ",&subject)
  2938.             }
  2939.             case line[x+1] of {
  2940.             "@": Op := "activate"
  2941.             "*": Op := "size"
  2942.             "!": Op := "foreach"
  2943.             "?": Op := "random"
  2944.             default: halt("readline: unknown operator $",line[x+1])
  2945.             }
  2946.             count +:= 1
  2947.             line[x:0] :=
  2948.             "(__self"||count||" := "||id||").__methods."||
  2949.             Op||"(__self"||count||".__state)"||tab(0)
  2950.         }
  2951.         } else {
  2952.         reverse(line[1:x])||" " ? {
  2953.             tab(many(white))
  2954.             if not (id := reverse(tab(many(alphadot)))) then {
  2955.               if not match(")") then halt("readline: can't parse")
  2956.               if not (id := reverse(tab(&pos<bal(&cset,')','('))))
  2957.             then halt("readline: can't bal ",&subject)
  2958.             }
  2959.             nummatched := &pos-1
  2960.         }
  2961.         if not (lp := find("(",z)) then halt("readline: expected '('")
  2962.         if z[lp+1] ~== ")" then c:="," else c:=""
  2963.         count +:= 1
  2964.         line[x-nummatched : x+lp+1] :=
  2965.           "(__self"||count||" := "||id||").__methods."||
  2966.             z[1:lp+1]||"__self"||count||".__state"||c
  2967.         }
  2968.     }
  2969.     return line
  2970.  
  2971.  
  2972.     } else fail
  2973. end
  2974. procedure readinput(name,phase)
  2975. #line 795 "idol.iol"
  2976.     if \loud then write("\t",name)
  2977.     fName := name
  2978.     fLine := 0
  2979.     fin   := sysopen(name,"r")
  2980.     while line := readln() do {
  2981.     line ? {
  2982.         tab(many(white))
  2983.         if ="class" then {
  2984.         decl := class()
  2985.         (__self1 := decl).__methods.read(__self1.__state,line,phase)
  2986.         if phase=1 then {
  2987.             (__self1 := decl).__methods.writemethods(__self1.__state)
  2988.             (__self1 := classes).__methods.insert(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state))
  2989.         } else (__self1 := classes).__methods.insert_t(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state))
  2990.         }
  2991.         else if ="procedure" then {
  2992.         if comp = 0 then comp := 1
  2993.         decl := method("")
  2994.         (__self1 := decl).__methods.read(__self1.__state,line,phase)
  2995.         (__self1 := decl).__methods.write(__self1.__state,fout,"")
  2996.         }
  2997.         else if ="record" then {
  2998.         if comp = 0 then comp := 1
  2999.         decl := declaration(line)
  3000.         (__self1 := decl).__methods.write(__self1.__state,fout,"")
  3001.         }
  3002.         else if ="global" then {
  3003.         if comp = 0 then comp := 1
  3004.         decl := Global(line)
  3005.         (__self1 := decl).__methods.write(__self1.__state,fout,"")
  3006.         }
  3007.         else if ="method" then {
  3008.         halt("readinput: method outside class")
  3009.         }
  3010.     }
  3011.     }
  3012.     close(fin)
  3013. end
  3014. procedure halt(args[])
  3015. #line 838 "idol.iol"
  3016.   errsrc()
  3017.   every writes(&errout,!args)
  3018.   stop()
  3019. end
  3020. procedure warn(args[])
  3021. #line 844 "idol.iol"
  3022.   errsrc()
  3023.   every writes(&errout,!args)
  3024.   write(&errout)
  3025. end
  3026. procedure errsrc()
  3027. #line 850 "idol.iol"
  3028.   writes(&errout,"\"",\fName,"\", line ",\fLine,": Idol/")
  3029. end
  3030. procedure tryopen(file,mode)
  3031. #line 856 "idol.iol"
  3032.   if f := open(file,mode) then return close(f)
  3033. end
  3034. procedure tryenvopen(file,mode)
  3035. #line 859 "idol.iol"
  3036.   return tryopen(envpath(file),mode)
  3037. end
  3038. procedure sysopen(file,mode)
  3039. #line 862 "idol.iol"
  3040.   if not (f := open(file,mode)) then
  3041.       halt("Couldn't open file ",file," for mode ",mode)
  3042.   return f
  3043. end
  3044. procedure envopen(file,mode)
  3045. #line 867 "idol.iol"
  3046.   return sysopen(envpath(file),mode)
  3047. end
  3048. procedure writelink(s)
  3049. #line 870 "idol.iol"
  3050.   write(fout,"link \"",s,"\"")
  3051. end
  3052. procedure icont(argstr,prefix)
  3053. #line 873 "idol.iol"
  3054. static s
  3055. initial { s := (getenv("ICONT")|"icont") }
  3056.   return mysystem(\prefix||s||argstr | s||argstr)
  3057. end
  3058. record idol_object(__state,__methods)
  3059.  
  3060. procedure declarationread(self,decl)
  3061. #line 169 "idol.iol"
  3062.     decl ? {
  3063.  
  3064.       tab(many(white))
  3065.       if not (self.tag := =("procedure"|"class"|"method"|"record")) then
  3066.     halt("declaration/read can't parse decl ",decl)
  3067.       tab(many(white))
  3068.  
  3069.       if not (self.name := tab(many(alpha))) then
  3070.     halt("declaration/read can't parse decl ",decl)
  3071.  
  3072.       if not tab(find("(")+1) then
  3073.       halt("declaration/read can't parse decl ",decl)
  3074.       tab(many(white))
  3075.       self.fields := classFields()
  3076.       if not ((__self1 := self.fields).__methods.parse(__self1.__state,tab(find(")")))) then
  3077.     halt("declaration/read can't parse decl ",decl)
  3078.     }
  3079.   end
  3080. procedure declarationwrite(self,f)
  3081. #line 192 "idol.iol"
  3082.      write(f,(__self1 := self).__methods.String(__self1.__state))
  3083.   end
  3084. procedure declarationString(self)
  3085. #line 198 "idol.iol"
  3086.     return self.tag || " " || self.name || "(" || (__self1 := self.fields).__methods.String(__self1.__state) || ")"
  3087.   end
  3088. record declaration_state(__state,__methods,name,fields,tag)
  3089. record declaration_methods(read,write,String,name)
  3090. global declaration__oprec
  3091. procedure declaration(name,fields,tag)
  3092. local self,clone
  3093. initial {
  3094.   if /declaration__oprec then declarationinitialize()
  3095.   }
  3096.   self := declaration_state(&null,declaration__oprec,name,fields,tag)
  3097.   self.__state := self
  3098.   declarationinitially(self)
  3099.   return idol_object(self,declaration__oprec)
  3100. end
  3101.  
  3102. procedure declarationinitialize()
  3103.   initial declaration__oprec := declaration_methods(declarationread,declarationwrite,declarationString,declarationname)
  3104. end
  3105. procedure declarationinitially(self)
  3106. #line 201 "idol.iol"
  3107.   if \self.name then (__self1 := self).__methods.read(__self1.__state,self.name)
  3108. end
  3109. procedure declarationname(self)
  3110.   return .(self.name)
  3111. end
  3112.  
  3113. procedure bodyread(self)
  3114. #line 210 "idol.iol"
  3115.     self.fn    := fName
  3116.     self.ln    := fLine
  3117.     self.text  := []
  3118.     while line := readln() do {
  3119.       put(self.text, line)
  3120.       line ? { tab(many(white)); if ="end" & &pos > *line then return }
  3121.     }
  3122.     halt("body/read: eof inside a procedure/method definition")
  3123.   end
  3124. procedure bodywrite(self,f)
  3125. #line 220 "idol.iol"
  3126.     if \self.ln then write(f,"#line ",self.ln," \"",self.fn,"\"")
  3127.     every write(f,(__self1 := self).__methods.foreach(__self1.__state)) 
  3128.   end
  3129. procedure bodydelete(self)
  3130. #line 224 "idol.iol"
  3131.     return pull(self.text)
  3132.   end
  3133. procedure bodysize(self)
  3134. #line 227 "idol.iol"
  3135.     return (*\ (self.text)) | 0
  3136.   end
  3137. procedure bodyforeach(self)
  3138. #line 230 "idol.iol"
  3139.     if t := \self.text then suspend !self.text
  3140.   end
  3141. record body_state(__state,__methods,fn,ln,text)
  3142. record body_methods(read,write,delete,size,foreach)
  3143. global body__oprec
  3144. procedure body(fn,ln,text)
  3145. local self,clone
  3146. initial {
  3147.   if /body__oprec then bodyinitialize()
  3148.   }
  3149.   self := body_state(&null,body__oprec,fn,ln,text)
  3150.   self.__state := self
  3151.   return idol_object(self,body__oprec)
  3152. end
  3153.  
  3154. procedure bodyinitialize()
  3155.   initial body__oprec := body_methods(bodyread,bodywrite,bodydelete,bodysize,bodyforeach)
  3156. end
  3157. procedure classread(self,line,phase)
  3158. #line 242 "idol.iol"
  3159.     (__self1 := self).__methods.declaration.read(__self1.__state,line)
  3160.     self.supers := idTaque(":")
  3161.     (__self1 := self.supers).__methods.parse(__self1.__state,line[find(":",line)+1:find("(",line)] | "")
  3162.     self.methods:= taque()
  3163.     self.text   := body()
  3164.     while line  := readln() do {
  3165.       line ? {
  3166.     tab(many(white))
  3167.     if ="initially" then {
  3168.         (__self1 := self.text).__methods.read(__self1.__state)
  3169.         if phase=2 then return
  3170.         (__self1 := self.text).__methods.delete(__self1.__state)    
  3171.                 
  3172.         return
  3173.     } else if ="method" then {
  3174.         decl := method(self.name)
  3175.         (__self1 := decl).__methods.read(__self1.__state,line,phase)
  3176.         (__self1 := self.methods).__methods.insert(__self1.__state,decl,(__self2 := decl).__methods.name(__self2.__state))
  3177.     } else if ="end" then {
  3178.     
  3179.         return
  3180.     } else if ="procedure" then {
  3181.         decl := Procedure("")
  3182.         (__self1 := decl).__methods.read(__self1.__state,line,phase)
  3183.         /self.glob := []
  3184.         put(self.glob,decl)
  3185.     } else if ="global" then {
  3186.         /self.glob := []
  3187.         put(self.glob,Global(line))
  3188.     } else if ="record" then {
  3189.         /self.glob := []
  3190.         put(self.glob,declaration(line))
  3191.     } else if upto(nonwhite) then {
  3192.         halt("class/read expected declaration on: ",line)
  3193.     }
  3194.       }
  3195.     }
  3196.     halt("class/read syntax error: eof inside a class definition")
  3197.   end
  3198. procedure classhas_initially(self)
  3199. #line 286 "idol.iol"
  3200.     return (__self1 := self.text).__methods.size(__self1.__state) > 0 
  3201.   end
  3202. procedure classispublic(self,fieldname)
  3203. #line 289 "idol.iol"
  3204.     if (__self1 := self.fields).__methods.ispublic(__self1.__state,fieldname) then return fieldname
  3205.   end
  3206. procedure classforeachmethod(self)
  3207. #line 292 "idol.iol"
  3208.     suspend (__self1 := self.methods).__methods.foreach(__self1.__state) 
  3209.   end
  3210. procedure classforeachsuper(self)
  3211. #line 295 "idol.iol"
  3212.     suspend (__self1 := self.supers).__methods.foreach(__self1.__state) 
  3213.   end
  3214. procedure classforeachfield(self)
  3215. #line 298 "idol.iol"
  3216.     suspend (__self1 := self.fields).__methods.foreach(__self1.__state) 
  3217.   end
  3218. procedure classtransitive_closure(self)
  3219. #line 301 "idol.iol"
  3220.     count := (__self1 := self.supers).__methods.size(__self1.__state) 
  3221.     while count > 0 do {
  3222.     added := taque()
  3223.     every sc := (__self1 := self.supers).__methods.foreach(__self1.__state) do { 
  3224.       if /(super := (__self1 := classes).__methods.lookup(__self1.__state,sc)) then
  3225.         halt("class/transitive_closure: couldn't find superclass ",sc)
  3226.       every supersuper := (__self1 := super).__methods.foreachsuper(__self1.__state) do {
  3227.         if / (__self1 := self.supers).__methods.lookup(__self1.__state,supersuper) &
  3228.          /(__self1 := added).__methods.lookup(__self1.__state,supersuper) then {
  3229.           (__self1 := added).__methods.insert(__self1.__state,supersuper)
  3230.         }
  3231.       }
  3232.     }
  3233.     count := (__self1 := added).__methods.size(__self1.__state) 
  3234.     every (__self1 := self.supers).__methods.insert(__self1.__state,(__self2 := added).__methods.foreach(__self2.__state)) 
  3235.     }
  3236.   end
  3237. procedure classwritedecl(self,f,s)
  3238. #line 323 "idol.iol"
  3239.     writes(f, s," ",self.name)
  3240.     if s=="class" & ( *(supers := (__self1 := self.supers).__methods.String(__self1.__state)) > 0 ) then
  3241.         writes(f," : ",supers)
  3242.     writes(f,"(")
  3243.     rv := (__self1 := self.fields).__methods.String(__self1.__state,s)
  3244.     if *rv > 0 then rv ||:= ","
  3245.     if s~=="class" & \self.ifields then        
  3246.       every l := !self.ifields do rv ||:= l.ident || ","
  3247.     writes(f,rv[1:-1])
  3248.     write(f,,")")
  3249.   end
  3250. procedure classwritespec(self,f)
  3251. #line 335 "idol.iol"
  3252.     f := envopen(filename(self.name),"w")
  3253.     (__self1 := self).__methods.writedecl(__self1.__state,f,"class")
  3254.     every (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.writedecl(__self2.__state,f,"method") 
  3255.     if (__self1 := self).__methods.has_initially(__self1.__state) then write(f,"initially")
  3256.     write(f,"end")
  3257.     close(f)
  3258.   end
  3259. procedure classwritemethods(self)
  3260. #line 348 "idol.iol"
  3261.     f:= envopen(filename(self.name)||".icn","w")
  3262.     every (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.write(__self2.__state,f,self.name) 
  3263.  
  3264.     if \self.glob & *self.glob>0 then {
  3265.     write(f,"#\n# globals declared within the class\n#")
  3266.     every i := 1 to *self.glob do (__self1 := (self.glob[i])).__methods.write(__self1.__state,f,"")
  3267.     }
  3268.     close(f)
  3269.   end
  3270. procedure classwrite(self)
  3271. #line 362 "idol.iol"
  3272.     f:= envopen(filename(self.name)||".icn","a")
  3273.  
  3274.  
  3275.  
  3276.     if /self.ifields then (__self1 := self).__methods.resolve(__self1.__state)
  3277.  
  3278.  
  3279.  
  3280.  
  3281.     writes(f,"record ",self.name,"_state(__state,__methods")
  3282.     rv := ","
  3283.     rv ||:= (__self1 := self.fields).__methods.idTaque.String(__self1.__state)        
  3284.     if rv[-1] ~== "," then rv ||:= ","
  3285.     every s := (!self.ifields).ident do rv ||:= s || ","
  3286.     write(f,rv[1:-1],")")
  3287.  
  3288.  
  3289.  
  3290.  
  3291.     writes(f,"record ",self.name,"_methods(")
  3292.     rv := ""
  3293.  
  3294.     every s := (((__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.name(__self2.__state))    |     
  3295.         (__self1 := self.fields).__methods.foreachpublic(__self1.__state)    |    
  3296.         (!self.imethods).ident        |    
  3297.         (__self1 := self.supers).__methods.foreach(__self1.__state))                 
  3298.     do rv ||:= s || ","
  3299.  
  3300.     if *rv>0 then rv[-1] := ""            
  3301.     write(f,rv,")")
  3302.  
  3303.  
  3304.  
  3305.  
  3306.  
  3307.     writes(f,"global ",self.name,"__oprec")
  3308.     every writes(f,", ", (__self1 := self.supers).__methods.foreach(__self1.__state),"__oprec") 
  3309.     write(f)
  3310.  
  3311.  
  3312.  
  3313.  
  3314.  
  3315.     (__self1 := self).__methods.writedecl(__self1.__state,f,"procedure")
  3316.     write(f,"local self,clone")
  3317.  
  3318.  
  3319.  
  3320.  
  3321.     write(f,"initial {\n",
  3322.         "  if /",self.name,"__oprec then ",self.name,"initialize()")
  3323.     if (__self1 := self.supers).__methods.size(__self1.__state) > 0 then 
  3324.     every (super <- (__self1 := self.supers).__methods.foreach(__self1.__state)) ~== self.name do 
  3325.         write(f,"  if /",super,"__oprec then ",super,"initialize()\n",
  3326.             "  ",self.name,"__oprec.",super," := ", super,"__oprec")
  3327.     write(f,"  }")
  3328.  
  3329.  
  3330.  
  3331.  
  3332.     writes(f,"  self := ",self.name,"_state(&null,",self.name,"__oprec")
  3333.     every writes(f,",",(__self1 := self.fields).__methods.foreach(__self1.__state)) 
  3334.     if \self.ifields then every writes(f,",",(!self.ifields).ident)
  3335.     write(f,")\n  self.__state := self")
  3336.  
  3337.  
  3338.  
  3339.  
  3340.     if (__self1 := self.text).__methods.size(__self1.__state) > 0 then write(f,"  ",self.name,"initially(self)") 
  3341.  
  3342.  
  3343.  
  3344.  
  3345.     if (__self1 := self.supers).__methods.size(__self1.__state) > 0 then { 
  3346.     every (super <- (__self1 := self.supers).__methods.foreach(__self1.__state)) ~== self.name do { 
  3347.         if (__self2 := ((__self1 := classes).__methods.lookup(__self1.__state,super))).__methods.has_initially(__self2.__state) then {
  3348.         if /madeclone := 1 then {
  3349.             write(f,"  clone := ",self.name,"_state()\n",
  3350.             "  clone.__state := clone\n",
  3351.             "  clone.__methods := ",self.name,"__oprec")
  3352.         }
  3353.         write(f,"  # inherited initialization from class ",super)
  3354.         write(f,"    every i := 2 to *self do clone[i] := self[i]\n",
  3355.             "    ",super,"initially(clone)")
  3356.         every l := !self.ifields do {
  3357.             if l.class == super then
  3358.             write(f,"    self.",l.ident," := clone.",l.ident)
  3359.         }
  3360.         }
  3361.     }
  3362.     }
  3363.  
  3364.  
  3365.  
  3366.  
  3367.  
  3368.  
  3369.     write(f,"  return idol_object(self,",self.name,"__oprec)\n",
  3370.         "end\n")
  3371.  
  3372.  
  3373.  
  3374.  
  3375.     write(f,"procedure ",self.name,"initialize()")
  3376.     writes(f,"  initial ",self.name,"__oprec := ",self.name,"_methods")
  3377.     rv := "("
  3378.     every s := (__self2 := ((__self1 := self.methods).__methods.foreach(__self1.__state))).__methods.name(__self2.__state) do {         
  3379.       if *rv>1 then rv ||:= ","
  3380.       rv ||:= self.name||s
  3381.     }
  3382.     every me := (__self1 := self.fields).__methods.foreachpublic(__self1.__state) do {    
  3383.       if *rv>1 then rv ||:= ","            
  3384.       rv ||:= self.name||me
  3385.     }
  3386.     every l := !self.imethods do {            
  3387.       if *rv>1 then rv ||:= ","
  3388.       rv ||:= l.class||l.ident
  3389.     }
  3390.     write(f,rv,")\n","end")
  3391.  
  3392.  
  3393.  
  3394.     if (__self1 := self).__methods.has_initially(__self1.__state) then {
  3395.     write(f,"procedure ",self.name,"initially(self)")
  3396.     (__self1 := self.text).__methods.write(__self1.__state,f)
  3397.     write(f,"end")
  3398.     }
  3399.  
  3400.  
  3401.  
  3402.  
  3403.     every me := (__self1 := self.fields).__methods.foreachpublic(__self1.__state) do {
  3404.       write(f,"procedure ",self.name,me,"(self)")
  3405.       if \strict then {
  3406.     write(f,"  if type(self.",me,") == ",
  3407.         "(\"list\"|\"table\"|\"set\"|\"record\") then\n",
  3408.         "    runerr(501,\"idol: scalar type expected\")")
  3409.     }
  3410.       write(f,"  return .(self.",me,")")
  3411.       write(f,"end")
  3412.       write(f)
  3413.     }
  3414.  
  3415.     close(f)
  3416.  
  3417.   end
  3418. procedure classresolve(self)
  3419. #line 513 "idol.iol"
  3420.  
  3421.  
  3422.  
  3423.     self.imethods := []
  3424.     self.ifields := []
  3425.     ipublics := []
  3426.     addedfields := table()
  3427.     addedmethods := table()
  3428.     every sc := (__self1 := self.supers).__methods.foreach(__self1.__state) do { 
  3429.     if /(superclass := (__self1 := classes).__methods.lookup(__self1.__state,sc)) then
  3430.         halt("class/resolve: couldn't find superclass ",sc)
  3431.     every superclassfield := (__self1 := superclass).__methods.foreachfield(__self1.__state) do {
  3432.         if /(__self1 := self.fields).__methods.lookup(__self1.__state,superclassfield) &
  3433.            /addedfields[superclassfield] then {
  3434.         addedfields[superclassfield] := superclassfield
  3435.         put ( self.ifields , classident(sc,superclassfield) )
  3436.         if (__self1 := superclass).__methods.ispublic(__self1.__state,superclassfield) then
  3437.             put( ipublics, classident(sc,superclassfield) )
  3438.         } else if \strict then {
  3439.         warn("class/resolve: '",sc,"' field '",superclassfield,
  3440.              "' is redeclared in subclass ",self.name)
  3441.         }
  3442.     }
  3443.     every superclassmethod := (__self2 := ((__self1 := superclass).__methods.foreachmethod(__self1.__state))).__methods.name(__self2.__state) do {
  3444.         if /(__self1 := self.methods).__methods.lookup(__self1.__state,superclassmethod) &
  3445.            /addedmethods[superclassmethod] then {
  3446.         addedmethods[superclassmethod] := superclassmethod
  3447.         put ( self.imethods, classident(sc,superclassmethod) )
  3448.         }
  3449.     }
  3450.     every public := (!ipublics) do {
  3451.         if public.class == sc then
  3452.         put (self.imethods, classident(sc,public.ident))
  3453.     }
  3454.     }
  3455.   end
  3456. #
  3457. # globals declared within the class
  3458. #
  3459. record classident(class,ident)
  3460. record class_state(__state,__methods,supers,methods,text,imethods,ifields,glob,name,fields,tag)
  3461. record class_methods(read,has_initially,ispublic,foreachmethod,foreachsuper,foreachfield,transitive_closure,writedecl,writespec,writemethods,write,resolve,String,name,declaration)
  3462. global class__oprec, declaration__oprec
  3463. procedure class(supers,methods,text,imethods,ifields,glob,name,fields,tag)
  3464. local self,clone
  3465. initial {
  3466.   if /class__oprec then classinitialize()
  3467.   if /declaration__oprec then declarationinitialize()
  3468.   class__oprec.declaration := declaration__oprec
  3469.   }
  3470.   self := class_state(&null,class__oprec,supers,methods,text,imethods,ifields,glob,name,fields,tag)
  3471.   self.__state := self
  3472.   clone := class_state()
  3473.   clone.__state := clone
  3474.   clone.__methods := class__oprec
  3475.   # inherited initialization from class declaration
  3476.     every i := 2 to *self do clone[i] := self[i]
  3477.     declarationinitially(clone)
  3478.     self.name := clone.name
  3479.     self.fields := clone.fields
  3480.     self.tag := clone.tag
  3481.   return idol_object(self,class__oprec)
  3482. end
  3483.  
  3484. procedure classinitialize()
  3485.   initial class__oprec := class_methods(classread,classhas_initially,classispublic,classforeachmethod,classforeachsuper,classforeachfield,classtransitive_closure,classwritedecl,classwritespec,classwritemethods,classwrite,classresolve,declarationString,declarationname)
  3486. end
  3487. procedure methodread(self,line,phase)
  3488. #line 556 "idol.iol"
  3489.     (__self1 := self).__methods.declaration.read(__self1.__state,line)
  3490.     self.text := body()
  3491.     if phase = 1 then
  3492.       (__self1 := self.text).__methods.read(__self1.__state)
  3493.   end
  3494. procedure methodwritedecl(self,f,s)
  3495. #line 562 "idol.iol"
  3496.     decl := (__self1 := self).__methods.String(__self1.__state)
  3497.     if s == "method" then decl[1:upto(white,decl)] := "method"
  3498.     else {
  3499.     decl[1:upto(white,decl)] := "procedure"
  3500.     decl[upto(white,decl)] ||:= self.class
  3501.     if *self.class ~= 0 then {
  3502.         i := find("(",decl)
  3503.         decl[i] ||:= "self" || (((decl[i+1] ~== ")"), ",") | "")
  3504.     }
  3505.     }
  3506.     write(f,decl)
  3507.   end
  3508. procedure methodwrite(self,f)
  3509. #line 575 "idol.iol"
  3510.     if self.name ~== "initially" then
  3511.     (__self1 := self).__methods.writedecl(__self1.__state,f,"procedure")
  3512.     (__self1 := self.text).__methods.write(__self1.__state,f)
  3513.     self.text := &null            
  3514.   end
  3515. record method_state(__state,__methods,class,text,name,fields,tag)
  3516. record method_methods(read,writedecl,write,String,name,declaration)
  3517. global method__oprec, declaration__oprec
  3518. procedure method(class,text,name,fields,tag)
  3519. local self,clone
  3520. initial {
  3521.   if /method__oprec then methodinitialize()
  3522.   if /declaration__oprec then declarationinitialize()
  3523.   method__oprec.declaration := declaration__oprec
  3524.   }
  3525.   self := method_state(&null,method__oprec,class,text,name,fields,tag)
  3526.   self.__state := self
  3527.   clone := method_state()
  3528.   clone.__state := clone
  3529.   clone.__methods := method__oprec
  3530.   # inherited initialization from class declaration
  3531.     every i := 2 to *self do clone[i] := self[i]
  3532.     declarationinitially(clone)
  3533.     self.name := clone.name
  3534.     self.fields := clone.fields
  3535.     self.tag := clone.tag
  3536.   return idol_object(self,method__oprec)
  3537. end
  3538.  
  3539. procedure methodinitialize()
  3540.   initial method__oprec := method_methods(methodread,methodwritedecl,methodwrite,declarationString,declarationname)
  3541. end
  3542. procedure Globalwrite(self,f)
  3543. #line 587 "idol.iol"
  3544.     write(f,self.s)
  3545.   end
  3546. record Global_state(__state,__methods,s)
  3547. record Global_methods(write)
  3548. global Global__oprec
  3549. procedure Global(s)
  3550. local self,clone
  3551. initial {
  3552.   if /Global__oprec then Globalinitialize()
  3553.   }
  3554.   self := Global_state(&null,Global__oprec,s)
  3555.   self.__state := self
  3556.   return idol_object(self,Global__oprec)
  3557. end
  3558.  
  3559. procedure Globalinitialize()
  3560.   initial Global__oprec := Global_methods(Globalwrite)
  3561. end
  3562. procedure Tablesize(self)
  3563. #line 596 "idol.iol"
  3564.     return (* \ self.t) | 0
  3565.   end
  3566. procedure Tableinsert(self,x,key)
  3567. #line 599 "idol.iol"
  3568.     /self.t := table()
  3569.     /key := x
  3570.     if / (self.t[key]) := x then return
  3571.   end
  3572. procedure Tablelookup(self,key)
  3573. #line 604 "idol.iol"
  3574.     if t := \self.t then return t[key]
  3575.     return
  3576.   end
  3577. procedure Tableforeach(self)
  3578. #line 608 "idol.iol"
  3579.     if t := \self.t then every suspend !self.t
  3580.   end
  3581. record Table_state(__state,__methods,t)
  3582. record Table_methods(size,insert,lookup,foreach)
  3583. global Table__oprec
  3584. procedure Table(t)
  3585. local self,clone
  3586. initial {
  3587.   if /Table__oprec then Tableinitialize()
  3588.   }
  3589.   self := Table_state(&null,Table__oprec,t)
  3590.   self.__state := self
  3591.   return idol_object(self,Table__oprec)
  3592. end
  3593.  
  3594. procedure Tableinitialize()
  3595.   initial Table__oprec := Table_methods(Tablesize,Tableinsert,Tablelookup,Tableforeach)
  3596. end
  3597. procedure taqueinsert(self,x,key)
  3598. #line 619 "idol.iol"
  3599.     /self.l := []
  3600.     if (__self1 := self).__methods.Table.insert(__self1.__state,x,key) then put(self.l,x)
  3601.   end
  3602. procedure taqueforeach(self)
  3603. #line 623 "idol.iol"
  3604.     if l := \self.l then every suspend !self.l
  3605.   end
  3606. procedure taqueinsert_t(self,x,key)
  3607. #line 626 "idol.iol"
  3608.     (__self1 := self).__methods.Table.insert(__self1.__state,x,key)
  3609.   end
  3610. procedure taqueforeach_t(self)
  3611. #line 629 "idol.iol"
  3612.     suspend (__self1 := self).__methods.Table.foreach(__self1.__state)
  3613.   end
  3614. record taque_state(__state,__methods,l,t)
  3615. record taque_methods(insert,foreach,insert_t,foreach_t,size,lookup,Table)
  3616. global taque__oprec, Table__oprec
  3617. procedure taque(l,t)
  3618. local self,clone
  3619. initial {
  3620.   if /taque__oprec then taqueinitialize()
  3621.   if /Table__oprec then Tableinitialize()
  3622.   taque__oprec.Table := Table__oprec
  3623.   }
  3624.   self := taque_state(&null,taque__oprec,l,t)
  3625.   self.__state := self
  3626.   return idol_object(self,taque__oprec)
  3627. end
  3628.  
  3629. procedure taqueinitialize()
  3630.   initial taque__oprec := taque_methods(taqueinsert,taqueforeach,taqueinsert_t,taqueforeach_t,Tablesize,Tablelookup)
  3631. end
  3632. procedure idTaqueparse(self,s)
  3633. #line 639 "idol.iol"
  3634.     s ? {
  3635.       tab(many(white))
  3636.       while name := tab(find(self.punc)) do {
  3637.     (__self1 := self).__methods.insert(__self1.__state,trim(name))
  3638.     move(1)
  3639.     tab(many(white))
  3640.       }
  3641.       if any(nonwhite) then (__self1 := self).__methods.insert(__self1.__state,trim(tab(0)))
  3642.     }
  3643.     return
  3644.   end
  3645. procedure idTaqueString(self)
  3646. #line 651 "idol.iol"
  3647.     if /self.l then return ""
  3648.     out := ""
  3649.     every id := !self.l do out ||:= id||self.punc
  3650.     return out[1:-1]
  3651.   end
  3652. record idTaque_state(__state,__methods,punc,l,t)
  3653. record idTaque_methods(parse,String,insert,foreach,insert_t,foreach_t,size,lookup,taque,Table)
  3654. global idTaque__oprec, taque__oprec, Table__oprec
  3655. procedure idTaque(punc,l,t)
  3656. local self,clone
  3657. initial {
  3658.   if /idTaque__oprec then idTaqueinitialize()
  3659.   if /taque__oprec then taqueinitialize()
  3660.   idTaque__oprec.taque := taque__oprec
  3661.   if /Table__oprec then Tableinitialize()
  3662.   idTaque__oprec.Table := Table__oprec
  3663.   }
  3664.   self := idTaque_state(&null,idTaque__oprec,punc,l,t)
  3665.   self.__state := self
  3666.   return idol_object(self,idTaque__oprec)
  3667. end
  3668.  
  3669. procedure idTaqueinitialize()
  3670.   initial idTaque__oprec := idTaque_methods(idTaqueparse,idTaqueString,taqueinsert,taqueforeach,taqueinsert_t,taqueforeach_t,Tablesize,Tablelookup)
  3671. end
  3672. procedure argListinsert(self,s)
  3673. #line 663 "idol.iol"
  3674.     if \self.varg then halt("variable arg must be final")
  3675.     if i := find("[",s) then {
  3676.       if not (j := find("]",s)) then halt("variable arg expected ]")
  3677.       s[i : j+1] := ""
  3678.       self.varg := s := trim(s)
  3679.     }
  3680.     (__self1 := self).__methods.idTaque.insert(__self1.__state,s)
  3681.   end
  3682. procedure argListString(self)
  3683. #line 672 "idol.iol"
  3684.     return (__self1 := self).__methods.idTaque.String(__self1.__state) || ((\self.varg & "[]") | "")
  3685.   end
  3686. record argList_state(__state,__methods,varg,punc,l,t)
  3687. record argList_methods(insert,String,varg,parse,foreach,insert_t,foreach_t,size,lookup,idTaque,taque,Table)
  3688. global argList__oprec, idTaque__oprec, taque__oprec, Table__oprec
  3689. procedure argList(varg,punc,l,t)
  3690. local self,clone
  3691. initial {
  3692.   if /argList__oprec then argListinitialize()
  3693.   if /idTaque__oprec then idTaqueinitialize()
  3694.   argList__oprec.idTaque := idTaque__oprec
  3695.   if /taque__oprec then taqueinitialize()
  3696.   argList__oprec.taque := taque__oprec
  3697.   if /Table__oprec then Tableinitialize()
  3698.   argList__oprec.Table := Table__oprec
  3699.   }
  3700.   self := argList_state(&null,argList__oprec,varg,punc,l,t)
  3701.   self.__state := self
  3702.   argListinitially(self)
  3703.   return idol_object(self,argList__oprec)
  3704. end
  3705.  
  3706. procedure argListinitialize()
  3707.   initial argList__oprec := argList_methods(argListinsert,argListString,argListvarg,idTaqueparse,taqueforeach,taqueinsert_t,taqueforeach_t,Tablesize,Tablelookup)
  3708. end
  3709. procedure argListinitially(self)
  3710. #line 675 "idol.iol"
  3711.   self.punc := ","
  3712. end
  3713. procedure argListvarg(self)
  3714.   return .(self.varg)
  3715. end
  3716.  
  3717. procedure classFieldsString(self,s)
  3718. #line 683 "idol.iol"
  3719.     if *(rv := (__self1 := self).__methods.argList.String(__self1.__state)) = 0 then return ""
  3720.     if /s | (s ~== "class") then return rv
  3721.     if (__self1 := self).__methods.ispublic(__self1.__state,self.l[1]) then rv := "public "||rv
  3722.     every field:=(__self1 := self).__methods.foreachpublic(__self1.__state) do rv[find(","||field,rv)] ||:= "public "
  3723.     return rv
  3724.   end
  3725. procedure classFieldsforeachpublic(self)
  3726. #line 690 "idol.iol"
  3727.     if \self.publics then every suspend !self.publics
  3728.   end
  3729. procedure classFieldsispublic(self,s)
  3730. #line 693 "idol.iol"
  3731.     if \self.publics then every suspend !self.publics == s
  3732.   end
  3733. procedure classFieldsinsert(self,s)
  3734. #line 696 "idol.iol"
  3735.     s ? {
  3736.       if ="public" & tab(many(white)) then {
  3737.     s := tab(0)
  3738.     /self.publics := []
  3739.     put(self.publics,s)
  3740.       }
  3741.     }
  3742.     (__self1 := self).__methods.argList.insert(__self1.__state,s)
  3743.   end
  3744. record classFields_state(__state,__methods,publics,varg,punc,l,t)
  3745. record classFields_methods(String,foreachpublic,ispublic,insert,varg,parse,foreach,insert_t,foreach_t,size,lookup,argList,idTaque,taque,Table)
  3746. global classFields__oprec, argList__oprec, idTaque__oprec, taque__oprec, Table__oprec
  3747. procedure classFields(publics,varg,punc,l,t)
  3748. local self,clone
  3749. initial {
  3750.   if /classFields__oprec then classFieldsinitialize()
  3751.   if /argList__oprec then argListinitialize()
  3752.   classFields__oprec.argList := argList__oprec
  3753.   if /idTaque__oprec then idTaqueinitialize()
  3754.   classFields__oprec.idTaque := idTaque__oprec
  3755.   if /taque__oprec then taqueinitialize()
  3756.   classFields__oprec.taque := taque__oprec
  3757.   if /Table__oprec then Tableinitialize()
  3758.   classFields__oprec.Table := Table__oprec
  3759.   }
  3760.   self := classFields_state(&null,classFields__oprec,publics,varg,punc,l,t)
  3761.   self.__state := self
  3762.   classFieldsinitially(self)
  3763.   clone := classFields_state()
  3764.   clone.__state := clone
  3765.   clone.__methods := classFields__oprec
  3766.   # inherited initialization from class argList
  3767.     every i := 2 to *self do clone[i] := self[i]
  3768.     argListinitially(clone)
  3769.     self.varg := clone.varg
  3770.   return idol_object(self,classFields__oprec)
  3771. end
  3772.  
  3773. procedure classFieldsinitialize()
  3774.   initial classFields__oprec := classFields_methods(classFieldsString,classFieldsforeachpublic,classFieldsispublic,classFieldsinsert,argListvarg,idTaqueparse,taqueforeach,taqueinsert_t,taqueforeach_t,Tablesize,Tablelookup)
  3775. end
  3776. procedure classFieldsinitially(self)
  3777. #line 706 "idol.iol"
  3778.   self.punc := ","
  3779. end
  3780. ##########
  3781. install.bat
  3782. rem msdos Idol installation
  3783. rem This compiles Idol in order to to test the system
  3784. icont -Sr1000 -SF30 -Si1000 idolboot msdos
  3785. mkdir idolcode.env
  3786. iconx idolboot -t -install
  3787. chdir idolcode.env
  3788. icont -c i_object
  3789. chdir ..
  3790. iconx idolboot idol msdos.icn
  3791. idolt
  3792. ##########
  3793. inverse.iol
  3794. class inverse:fraction(d)
  3795. initially
  3796.   self.n := 1
  3797. end
  3798.  
  3799. procedure main()
  3800.   x := inverse(2)
  3801.   y := fraction(3,4)
  3802.   z := x$times(y)
  3803.   write("The decimal equivalent of ",z$asString(),
  3804.     " is ",trim(z$asReal(),'0'))
  3805. end
  3806. ##########
  3807. itags.iol
  3808. # itags - an Icon/Idol tag generator by Nick Kline
  3809. # hacks (such as this header comment) by Clint Jeffery
  3810. # last edit: 12/13/89
  3811. #
  3812. # the output is a sorted list of lines of the form
  3813. # identifier  owning_scope  category_type  filename  lineno(:length)
  3814. #
  3815. # owning scope is the name of the class or procedure or record in which
  3816. # the tag is defined.
  3817. # category type is the kind of tag; one of:
  3818. # (global,procedure,record,class,method,param,obj_field,rec_field)
  3819. #
  3820. procedure main(args) 
  3821. local line, lineno, fout, i, fin, notvar, objects, actual_file, outlines
  3822.  
  3823. initial {
  3824.     fout := open("ITAGS", "w") | stop("can't open ITAGS for writing"); 
  3825.     outlines := [[0,0,0,0,0,0]]
  3826.     i := 1
  3827.     notid := &cset -- &ucase -- &digits -- &lcase -- '_'
  3828. }
  3829.  
  3830. if(*args=0) then 
  3831.     stop("usage: itags file1 [file2 ...]")
  3832.  
  3833. while i <= *args do {
  3834.     fin := open(args[i],"r") |
  3835.     stop("could not open file ",args[i]," exiting")
  3836.     lineno := 1
  3837.     objects := program( args[i] )
  3838.  
  3839.     while line := read(fin) do {
  3840.     line[upto('#',line):0] := ""
  3841.     line ? {
  3842.         tab(many(' ')) 
  3843.         
  3844.         if =("global") then {
  3845.         if(any(notid)) then 
  3846.             every objects$addvar( getword(), lineno )
  3847.         }
  3848.         
  3849.         if =("procedure")  then 
  3850.           if(any(notid)) then {
  3851.             objects$addproc( getword(), lineno )
  3852.             objects$myline(tab(0),lineno)
  3853.         }
  3854.         
  3855.  
  3856.         if =("class") then 
  3857.         if any(notid) then {
  3858.             objects$addclass( getword(), lineno )
  3859.             objects$myline(tab(0),lineno)
  3860.         }
  3861.  
  3862.  
  3863.         if =("method") then {
  3864.         if any(notid) then {
  3865.             objects$addmethod( getword(), lineno ) 
  3866.             objects$myline(tab(0),lineno)
  3867.         }
  3868.         }
  3869.  
  3870.         if =("local") then {
  3871.         if any(notid) then 
  3872.             every objects$addvar( getword(), lineno ) 
  3873.         }
  3874.  
  3875.         if =("static") then {
  3876.         if any(notid) then 
  3877.             every objects$addstat( getword(), lineno ) 
  3878.         }
  3879.  
  3880.         if =("record") then {
  3881.         if any(notid) then {
  3882.             objects$addrec( getword(), lineno ) 
  3883.             objects$myline(tab(0),lineno)
  3884.             objects$endline( lineno)
  3885.         }
  3886.         }
  3887.         if =("end") then
  3888.         objects$endline(lineno)
  3889.     }
  3890.     lineno +:= 1
  3891.     }
  3892.     objects$drawthyself(outlines)
  3893.     i +:= 1
  3894. }
  3895. # now process all the resulting lines
  3896. every i := 2 to *outlines do {
  3897.     outlines[i] := (
  3898.     left(outlines[i][1],outlines[1][1]+1) ||
  3899.     left(outlines[i][2],outlines[1][2]+1) ||
  3900.     left(outlines[i][3],outlines[1][3]+1) ||
  3901.     left(outlines[i][4],outlines[1][4]+1) ||
  3902.     left(outlines[i][5],outlines[1][5]) ||
  3903.     (if \outlines[i][6] then ":"||outlines[i][6] else ""))
  3904. }
  3905. outlines := outlines[2:0]
  3906. outlines := sort(outlines)
  3907. every write(fout,!outlines)
  3908. end
  3909.  
  3910. class functions(name, lineno,vars,lastline, parent, params,stat,paramtype)
  3911.  
  3912. method drawthyself(outfile)
  3913. local k
  3914.     every k := !self.vars do
  3915.       emit(outfile, k[1], self.name, "local", self.parent$myfile(),k[2])
  3916.     every k := !self.params do
  3917.       emit(outfile, k[1], self.name, self.paramtype, self.parent$myfile(),k[2])
  3918.     every k := !self.stat do
  3919.       emit(outfile, k[1], self.name, "static", self.parent$myfile(),k[2])
  3920. end
  3921.  
  3922. method myline(line,lineno)
  3923. local word
  3924. static ids,  letters
  3925. initial {
  3926.     ids := &lcase ++ &ucase ++ &digits ++ '_'
  3927.     letters := &ucase ++ &lcase
  3928. }
  3929.  
  3930. line ? while tab(upto(letters)) do  {
  3931.     word := tab(many(ids))
  3932.     self.params|||:= [[word,lineno]]
  3933. }
  3934.  
  3935. end
  3936.  
  3937. method addstat(varname, lineno)
  3938.     self.stat|||:=[[varname, lineno]]
  3939.     return
  3940. end
  3941.  
  3942. method addvar(varname, lineno)
  3943.     self.vars|||:=[[varname, lineno]]
  3944.     return
  3945. end
  3946.  
  3947. method endline( lineno )
  3948.    self.lastline := lineno
  3949. end
  3950.  
  3951. method resetcontext()
  3952.     self.parent$resetcontext()
  3953. end
  3954.  
  3955. initially
  3956.     self.vars := []
  3957.     self.params := []
  3958.     self.stat := []
  3959. end # end of class functions
  3960.  
  3961.  
  3962. class proc : functions(name,lineno, parent,paramtype)
  3963.  
  3964. method drawthyself(outfile)
  3965.     emit(outfile,self.name, "*" , "procedure", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1)
  3966.     self$functions.drawthyself(outfile)
  3967. end
  3968. initially
  3969.  self.paramtype := "param"
  3970. end # of class proc
  3971.  
  3972. class rec : functions(name, lineno, parent, line, paramtype)
  3973.  
  3974. method drawthyself(outfile)
  3975.     emit(outfile,self.name, "*", "record", self.parent$myfile(),
  3976.      self.lineno)
  3977.     self$functions.drawthyself(outfile)
  3978. end
  3979. initially
  3980.   paramtype := "rec_field"
  3981. end # class record
  3982.  
  3983.  
  3984.  
  3985. class program(public myfile, vars, proc, records, classes, curcontext, contextsave,globals)
  3986.  
  3987. method endline( lineno )
  3988.     self.curcontext$endline( lineno )
  3989.     self.curcontext := pop(self.contextsave)
  3990. end
  3991.  
  3992. method myline( line,lineno)
  3993.     self.curcontext$myline( line,lineno)
  3994. end
  3995.    
  3996. method drawthyself(outfile)
  3997.     every k := !self.globals do
  3998.     emit(outfile,k[1], "*", "global", self.myfile,k[2])
  3999.     every (!self.proc)$drawthyself(outfile)
  4000.     every (!self.records)$drawthyself(outfile)
  4001.     every (!self.classes)$drawthyself(outfile)
  4002. end
  4003.  
  4004. method addmethod(name, lineno)
  4005.     push(self.contextsave,self.curcontext)
  4006.     self.curcontext := self.curcontext$addmethod(name,lineno)
  4007.     return
  4008. end
  4009.  
  4010. method addstat(varname, lineno)
  4011.     self.curcontext$addstat(varname, lineno)
  4012. end
  4013.  
  4014. method addvar(varname, lineno)
  4015.     if self.curcontext === self
  4016.     then  self.globals|||:= [[varname,lineno]]
  4017.     else self.curcontext$addvar(varname,lineno)
  4018.     return
  4019. end
  4020.  
  4021. method addproc(procname, lineno)
  4022.     push(self.contextsave, self.curcontext)
  4023.     self.curcontext := proc(procname, lineno, self)
  4024.     self.proc|||:= [self.curcontext]
  4025.     return
  4026. end
  4027.  
  4028. method addrec(recname, lineno)
  4029.     push(self.contextsave, self.curcontext)
  4030.     self.curcontext := rec(recname, lineno,self)
  4031.     self.records|||:=[self.curcontext]
  4032.     return
  4033. end
  4034.  
  4035. method addclass(classname, lineno)
  4036.     push(self.contextsave, self.curcontext)
  4037.     self.curcontext := class_(classname, lineno, self)
  4038.     self.classes|||:=[self.curcontext]
  4039.     return
  4040. end
  4041.  
  4042. method resetcontext()
  4043.     self.curcontext := pop(self.contextsave)
  4044. end
  4045.  
  4046. initially 
  4047.  self.globals := []
  4048.  self.proc := []
  4049.  self.records := []
  4050.  self.classes := []
  4051.  self.curcontext := self
  4052.  self.contextsave := []
  4053. end  # end of class program
  4054.  
  4055.  
  4056.  
  4057. class class_ : functions (public name, lineno, parent, meth,paramtype)
  4058.  
  4059. method myfile()
  4060.     return self.parent$myfile()
  4061. end
  4062.  
  4063. method addmethod(methname, lineno)
  4064.     self.meth|||:= [methods(methname, lineno, self)]
  4065.     return (self.meth[-1])
  4066. end
  4067.  
  4068. method drawthyself(outfile)
  4069.     emit(outfile,self.name, "*" , "class", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1)    
  4070.     every (!self.meth)$drawthyself(outfile)
  4071.     self$functions.drawthyself(outfile)
  4072. end
  4073.  
  4074. initially
  4075.     self.meth := []
  4076.     self.paramtype := "obj_field"
  4077. end #end of class_
  4078.  
  4079. class methods: functions(name, lineno, parent,paramtype)
  4080. method drawthyself(outfile)
  4081.         emit(outfile,self.name, self.parent$name() , "method", self.parent$myfile(),self.lineno, self.lastline-self.lineno+1)    
  4082.     self$functions.drawthyself(outfile)
  4083. end
  4084. initially
  4085.     self.paramtype := "param"
  4086. end #end of members    class
  4087.  
  4088. procedure emit(outlist,ident, scope, type, filename, line, length)
  4089.     outlist[1][1] := outlist[1][1] < *ident
  4090.     outlist[1][2] := outlist[1][2] < *scope
  4091.     outlist[1][3] := outlist[1][3] < *type
  4092.     outlist[1][4] := outlist[1][4] < *filename
  4093.     outlist[1][5] := outlist[1][5] < *line
  4094.     outlist[1][6] := outlist[1][6] < *\length
  4095.     put( outlist, [ident,scope,type,filename,line,length] )
  4096. end
  4097.  
  4098.  
  4099. procedure getword()
  4100.     local word
  4101.     static ids,letts
  4102.     initial {
  4103.     ids := &ucase ++ &lcase ++ &digits ++ '_'
  4104.     letts := &ucase ++ &lcase
  4105.     }
  4106.  
  4107.     while tab(upto(letts)) do {
  4108.     word := tab(many(ids))
  4109.     suspend word
  4110.     }
  4111.  
  4112. end
  4113. ##########
  4114. labelgen.iol
  4115. class labelgen : Sequence(prefix,postfix)
  4116.   method activate()
  4117.     return self.prefix||self$Sequence.activate()||self.postfix
  4118.   end
  4119. initially
  4120.   /(self.prefix) := ""
  4121.   /(self.postfix) := ""
  4122.   /(self.bounds)  := [50000]
  4123. end
  4124. ##########
  4125. lbltest.iol
  4126. procedure main()
  4127.  label := labelgen("L",":")
  4128.   every i := 1 to 10 do write($@label)
  4129. end
  4130. ##########
  4131. main.iol
  4132. procedure main()
  4133.   mydeque := Deque()
  4134.   mydeque$push("hello")
  4135.   mydeque$push("world")
  4136.   write("My deque is size ",mydeque$size())
  4137.   every write("give me a ",mydeque$foreach())
  4138.   write("A random element is ",mydeque$random())
  4139.   write("getting ",mydeque$get()," popping ",mydeque$pop())
  4140. end
  4141. ##########
  4142. mpw.icn
  4143. #
  4144. # @(#)mpw.icn    1.2 3/13/90
  4145. # OS-specific code for Macintosh MPW
  4146. # Adapted from unix.icn by Charles Lakos
  4147. #
  4148. global lnkopt,env,sysok
  4149.  
  4150. procedure mysystem(s)
  4151.   if \loud then write(s)
  4152.   return system(s)
  4153. end
  4154.  
  4155. procedure filename(s)
  4156.   return s
  4157. end
  4158. procedure writesublink(s)
  4159.   writelink(env||"_"||s)
  4160. end
  4161. procedure envpath(filename)
  4162.   return env||"_"||filename
  4163. end
  4164. #
  4165. # Installation.
  4166. # Uses hierarchical filesystem on some systems (see initialize)
  4167. #
  4168. procedure install(args)
  4169.   write("Installing idol environment with prefix ",env)
  4170.   fout := envopen("i_object.icn","w")
  4171.   write(fout,"record idol_object(__state,__methods)")
  4172.   close(fout)
  4173.   fout := &null
  4174.   cdicont(["i_object"])
  4175. end
  4176.  
  4177. procedure makeexe(args,i)
  4178.   exe := args[i]
  4179.   if icont(lnkopt||exe) = \sysok then {
  4180.       mysystem("delete "||exe||".icn")
  4181.       if \exec then {
  4182.     write("Executing:")
  4183.     every i := exec+1 to *args do exe ||:= " "||args[i]
  4184.     mysystem(exe)
  4185.       }
  4186.   }
  4187. end
  4188. #
  4189. # system-dependent compilation of idolfile.icn
  4190. #   (in the idol subdirectory, if there is one)
  4191. #
  4192. procedure cdicont(idolfiles)
  4193.   args := " -c"
  4194.   rms  := ""
  4195.   every ifile := !idolfiles do args ||:= " " || envpath(ifile)
  4196.   every ifile := !idolfiles do rms  ||:= " " || envpath(ifile) || ".icn"
  4197.  
  4198.   if comp = -2 then return  # -t --> don't translate at all
  4199.   if icont(args,"") = \sysok
  4200.   then mysystem("delete "||rms)
  4201. end
  4202. procedure sysinitialize()
  4203.   lnkopt := " -Sr500 -SF30 -Si1000 "
  4204.   env:= "C"
  4205.   sysok := 0
  4206.   loud := &null
  4207.   write(&errout)
  4208.   write(&errout, "*** Select and run the following commands ***")
  4209.   write(&errout)
  4210. end
  4211.  
  4212. procedure system(s)
  4213.   write(&errout,s)
  4214.   return sysok
  4215. end
  4216. ##########
  4217. msdos.icn
  4218. #
  4219. # @(#)msdos.icn    1.3 3/13/90
  4220. # OS-specific code for MS-DOS Idol
  4221. #
  4222. # For systems which cannot run icont from within an Icon program,
  4223. # the approach is for Idol to generate a script/batch file to do this.
  4224. #
  4225. global lnkopt,cd,md,env,sysok,batfile
  4226.  
  4227. procedure mysystem(s)
  4228.   if /batfile then batfile := open("idolt.bat","w")
  4229.   if \loud then write(s)
  4230.   write(batfile,s)
  4231.   return sysok # system(s) # MS-DOS Icon is generally too big to use system()
  4232. end
  4233.  
  4234. procedure filename(s)
  4235.   s[9:0] := ""
  4236.   return s
  4237. end
  4238. procedure writesublink(s)
  4239.   writelink(env||"\\\\"||s)
  4240. end
  4241. procedure envpath(filename)
  4242.   return env||"\\"||filename
  4243. end
  4244. #
  4245. # Installation.
  4246. # Uses hierarchical filesystem on some systems (see initialize)
  4247. #
  4248. procedure install(args)
  4249.   write("Installing idol environment in ",env)
  4250.   if env ~== "" then mysystem(md||env)
  4251.   if fout := envopen("i_object.icn","w") then {
  4252.     write(fout,"record idol_object(__state,__methods)")
  4253.     close(fout)
  4254.   } else {
  4255.     if not (fout := open("i_object.icn","w")) then stop("can't open i_object")
  4256.     write(fout,"record idol_object(__state,__methods)")
  4257.     close(fout)
  4258.     mysystem("copy i_object.icn "||env)
  4259.     mysystem("del i_object.icn")
  4260.   }
  4261.   fout := &null
  4262.   cdicont(["i_object"])
  4263. end
  4264.  
  4265. procedure makeexe(args,i)
  4266.   exe := args[i]
  4267.   if icont(lnkopt||exe) = \sysok then {
  4268.       if \exec then {
  4269.     write("Executing:")
  4270.     exe := "iconx "||exe
  4271.     every i := exec+1 to *args do exe ||:= " "||args[i]
  4272.     mysystem(exe)
  4273.       }
  4274.   }
  4275. end
  4276. #
  4277. # system-dependent compilation of idolfile.icn
  4278. #   (in the idol subdirectory, if there is one)
  4279. #
  4280. procedure cdicont(idolfiles)
  4281.   if comp = -2 then return  # -t --> don't call icont at all
  4282.   args := " -c"
  4283.   rms  := ""
  4284.   every ifile := !idolfiles do args ||:= " " || ifile
  4285.   every ifile := !idolfiles do rms  ||:= " " || ifile || ".icn"
  4286.  
  4287.   mysystem("cd idolcode.env")
  4288.   icont(args)
  4289.   mysystem("cd ..")
  4290. end
  4291. procedure sysinitialize()
  4292.   lnkopt := " -Sr500 -SF30 -Si1000 "
  4293.   cd := "cd "
  4294.   md := "mkdir "
  4295.   env := "idolcode.env"
  4296.   sysok := 0
  4297. end
  4298. ##########
  4299. os2.icn
  4300. #
  4301. # @(#)os2.icn    1.3 3/13/90
  4302. # OS-specific code for OS/2 Idol
  4303. # Adapted from msdos.icn by cheyenne wills
  4304. #
  4305. global lnkopt,cd,md,env,sysok
  4306.  
  4307. procedure mysystem(s)
  4308.   if \loud then write(s)
  4309.   return system(s)
  4310. end
  4311.  
  4312. procedure filename(s)
  4313.   s[9:0] := ""
  4314.   return s
  4315. end
  4316. procedure writesublink(s)
  4317.   writelink(env||"\\\\"||s)
  4318. end
  4319. procedure envpath(filename)
  4320.   return env||"\\"||filename
  4321. end
  4322. #
  4323. # Installation.
  4324. # Uses hierarchical filesystem on some systems (see initialize)
  4325. #
  4326. procedure install(args)
  4327.   write("Installing idol environment in ",env)
  4328.   if env ~== "" then mysystem(md||env)
  4329.   fout := envopen("i_object.icn","w")
  4330.   write(fout,"record idol_object(__state,__methods)")
  4331.   close(fout)
  4332.   fout := &null
  4333.   cdicont(["i_object"])
  4334. end
  4335.  
  4336. procedure makeexe(args,i)
  4337.   exe := args[i]
  4338.   if icont(lnkopt||exe) = \sysok then {
  4339.       mysystem((if find("UNIX",&features) then "rm " else "del ")||exe||".icn")
  4340.       if \exec then {
  4341.     write("Executing:")
  4342.     if not find("UNIX",&features) then exe := "iconx "||exe
  4343.     every i := exec+1 to *args do exe ||:= " "||args[i]
  4344.     mysystem(exe)
  4345.       }
  4346.   }
  4347. end
  4348. #
  4349. # system-dependent compilation of idolfile.icn
  4350. #   (in the idol subdirectory, if there is one)
  4351. #
  4352. procedure cdicont(idolfiles)
  4353. initial { s := (getenv("ICONT")|"icont") }
  4354.  
  4355.   if comp = -2 then return  # -t --> don't call icont at all
  4356.   args := " -c"
  4357.   rms  := ""
  4358.   every ifile := !idolfiles do args ||:= " " || ifile
  4359.   every ifile := !idolfiles do rms  ||:= " " || ifile || ".icn"
  4360.   cdcmd := open("idolenv.cmd","w")
  4361.   write(cdcmd,"@echo off")
  4362.   write(cdcmd,"cd idolcode.env")
  4363.   write(cdcmd,s,args)
  4364.   write(cdcmd,"if errorlevel 1 goto xit")
  4365.   every ifile := !idolfiles do
  4366.     write(cdcmd,"del ",ifile,".icn")
  4367.   write(cdcmd,":xit")
  4368.   write(cdcmd,"cd ..")
  4369.   close(cdcmd)
  4370.   mysystem("idolenv.cmd")
  4371.   mysystem("del idolenv.cmd")
  4372. end
  4373. procedure sysinitialize()
  4374.   lnkopt := " -Sr500 -SF30 -Si1000 "
  4375.   cd := "cd "
  4376.   md := "mkdir "
  4377.   env := "idolcode.env"
  4378.   sysok := 0
  4379. end
  4380. ##########
  4381. point.iol
  4382. class Cartesian : Radian (x,y)
  4383. initially
  4384.   if /(self.r) then {
  4385.     self.r := sqrt(self.x^2+self.y^2)
  4386.     self.d := 0 # this should really be some awful mess
  4387.   }
  4388. end
  4389. class Radian : Cartesian(d,r)
  4390. initially
  4391.   if /(self.x) then {
  4392.     self.x := 0
  4393.     self.y := 0
  4394.   }
  4395. end
  4396. ##########
  4397. seqtest.iol
  4398. procedure main()
  4399.   decimal   := sequence(255)
  4400.   hex       := sequence("0123456789ABCDEF","0123456789ABCDEF")
  4401.   octal     := sequence(3,7,7)
  4402.   character := sequence(string(&cset))
  4403.   while write(right($@decimal,3)," ",$@hex," ",$@octal," ",image($@character))
  4404. end
  4405. ##########
  4406. sequence.iol
  4407. procedure sequence(bounds[ ])
  4408.   return Sequence(bounds)
  4409. end
  4410.  
  4411. class Sequence(bounds,indices)
  4412.   method max(i)
  4413.     elem := self.bounds[i]
  4414.     return (type(elem)== "integer",elem) | *elem-1
  4415.   end
  4416.   method elem(i)
  4417.     elem := self.bounds[i]
  4418.     return (type(elem)== "integer",self.indices[i]) | elem[self.indices[i]+1]
  4419.   end
  4420.   method activate()
  4421.     top := *(self.indices)
  4422.     if self.indices[1] > self$max(1) then fail
  4423.     s := ""
  4424.     every i := 1 to top do {
  4425.       s ||:= self$elem(i)
  4426.     }
  4427.     repeat {
  4428.        self.indices[top] +:= 1
  4429.        if top=1 | (self.indices[top] <= self$max(top)) then break
  4430.        self.indices[top] := 0
  4431.        top -:= 1
  4432.     }
  4433.     return s
  4434.   end
  4435. initially
  4436.   / (self.indices) := list(*self.bounds,0)
  4437. end
  4438. ##########
  4439. systems.doc
  4440. This file contains system-dependent notes on Idol.  Compiling idolboot
  4441. for your system now requires a command of the form
  4442.     icont -Sr1000 -SF30 -Si1000 idolboot system
  4443. where system is the name of your system (so far unix, msdos, os2, or vms).
  4444.  
  4445. UNIX
  4446.  
  4447. If you are running UNIX, count yourself lucky!
  4448.  
  4449. MSDOS
  4450. Due to memory limitations, Idol for MS-DOS Icon does not use the system()
  4451. function.  Instead, it generates a batch file, idolt.bat, containing the
  4452. sequence of commands required to finish the translation and linking of
  4453. the output into executable icode.  The batch file idol.bat runs idol
  4454. and then calls idolt for you; it should suffice in ordinary situations.
  4455. It is invoked as described in the man page and reference manual, e.g.
  4456.     C> idol idol msdos
  4457. The file install.bat performs the initial bootstrap translation of idol.
  4458. Note that the translation scripts cannot automatically remove .icn files,
  4459. so you may have to remove them manually if your disk space is precious.
  4460.  
  4461. VMS
  4462.  
  4463. Idol compiles and runs under VMS Icon version 7.0, but its a little
  4464. klunky; idol may fail to execute icont, or icont may fail to execute
  4465. ilink (under version 7.0).  Unfortunately I do not have access
  4466. to a VMS machine running a current version of Icon.  Note that there
  4467. are two DCL scripts in the distribution: vms.com is used by Idol
  4468. internally, while idol.com is a convenience script if icont fails
  4469. on your system when invoked from inside Idol.  Remember
  4470. when specifying options to either idol or icont one must put quotes
  4471. around the argument in order for VMS to leave it alone!
  4472.  
  4473. OS/2
  4474.  
  4475. Cheyenne Wills has provided us all with an OS/2 system file!
  4476. Although problems should be reported to me, the credit is all his.
  4477.  
  4478. MPW
  4479.  
  4480. Charles Lakos has provided a system file for Icon running under the
  4481. Macintosh Programmer's Workshop.  Icon source for class X is generated
  4482. as C_X.icn.  After the Idol translation phase, the commands  for the
  4483. Icon translation have been written to the MPW Worksheet.  They can 
  4484. simply be selected and run.  Thanks Charles!
  4485.  
  4486. AMIGA
  4487.  
  4488. Idol runs fairly comfortably on Version 8 of Amiga Icon (it won't work
  4489. with Version 7.5 of Amiga Icon).  Version 8 of Amiga Icon isn't
  4490. available at this writing, but probably will be by the time you read this.
  4491.  
  4492.  
  4493. OTHERS
  4494.  
  4495. Porting idol consists of writing a new system.icn file for your system.
  4496. Take a look at unix.icn, vms.icn, os2.icn, mpw.icn, and msdos.icn.
  4497. ##########
  4498. unix.icn
  4499. #
  4500. # @(#)unix.icn    1.3 3/13/90
  4501. # OS-specific code for UNIX Idol
  4502. #
  4503. global lnkopt,env,sysok
  4504.  
  4505. procedure mysystem(s)
  4506.   if \loud then write(s)
  4507.   return system(s)
  4508. end
  4509.  
  4510. procedure filename(s)
  4511.   s[9:0] := ""
  4512.   return s
  4513. end
  4514. procedure writesublink(s)
  4515.   writelink(env||"/"||s)
  4516. end
  4517. procedure envpath(filename)
  4518.   return env||"/"||filename
  4519. end
  4520. #
  4521. # Installation.
  4522. # Uses hierarchical filesystem on some systems (see initialize)
  4523. #
  4524. procedure install(args)
  4525.   write("Installing idol environment in ",env)
  4526.   if env ~== "" then mysystem("mkdir "||env)
  4527.   fout := envopen("i_object.icn","w")
  4528.   write(fout,"record idol_object(__state,__methods)")
  4529.   close(fout)
  4530.   fout := &null
  4531.   cdicont(["i_object"])
  4532. end
  4533.  
  4534. procedure makeexe(args,i)
  4535.   exe := args[i]
  4536.   if icont(lnkopt||exe) = \sysok then {
  4537.       mysystem("rm "||exe||".icn")
  4538.       if \exec then {
  4539.     write("Executing:")
  4540.     every i := exec+1 to *args do exe ||:= " "||args[i]
  4541.     mysystem(exe)
  4542.       }
  4543.   }
  4544. end
  4545. #
  4546. # system-dependent compilation of idolfile.icn
  4547. #   (in the idol subdirectory, if there is one)
  4548. #
  4549. procedure cdicont(idolfiles)
  4550.   args := " -c"
  4551.   rms  := ""
  4552.   every ifile := !idolfiles do args ||:= " " || ifile
  4553.   every ifile := !idolfiles do rms  ||:= " " || ifile || ".icn"
  4554.  
  4555.   if comp = -2 then return  # -t --> don't translate at all
  4556.   if icont(args,"cd idolcode.env; ") = \sysok
  4557.   then mysystem("cd idolcode.env; rm "||rms)
  4558. end
  4559. procedure sysinitialize()
  4560.   lnkopt := " -Sr500 -SF30 -Si1000 "
  4561.   env:= "idolcode.env"
  4562.   sysok := 0
  4563. end
  4564. ##########
  4565. vms.com
  4566. $ ! A script used internally by Idol on VMS
  4567. $ set default [.idolenv]
  4568. $ icont -c 'P1'
  4569. $ set default [-]
  4570. ##########
  4571. vms.icn
  4572. #
  4573. # @(#)vms.icn    1.4 3/13/90
  4574. # OS-specific code for VMS Idol
  4575. #
  4576. global lnkopt,cd,md,env,sysok
  4577.  
  4578. procedure mysystem(s)
  4579.   if \loud then write(s)
  4580.   return system(s)
  4581. end
  4582.  
  4583. procedure filename(s)
  4584.   s[9:0] := ""
  4585.   return s
  4586. end
  4587. procedure writesublink(s)
  4588.   writelink(env||s)
  4589. end
  4590. procedure envpath(filename)
  4591.   return env||filename
  4592. end
  4593. #
  4594. # Installation.
  4595. # Uses hierarchical filesystem on some systems (see initialize)
  4596. #
  4597. procedure install(args)
  4598.   write("Installing idol environment in ",env)
  4599.   if env ~== "" then mysystem(md||env)
  4600.   fout := envopen("i_object.icn","w")
  4601.   write(fout,"record idol_object(__state,__methods)")
  4602.   close(fout)
  4603.   fout := &null
  4604.   cdicont(["i_object"])
  4605. end
  4606.  
  4607. procedure makeexe(args,i)
  4608.   exe := args[i]
  4609.   if icont(lnkopt||exe) = \sysok then {
  4610.       mysystem("del "||exe||".icn")
  4611.       if \exec then {
  4612.     write("Executing:")
  4613.     exe := "iconx "||exe
  4614.     every i := exec+1 to *args do exe ||:= " "||args[i]
  4615.     mysystem(exe)
  4616.       }
  4617.   }
  4618. end
  4619. #
  4620. # system-dependent compilation of idolfile.icn
  4621. #   (in the idol subdirectory, if there is one)
  4622. #
  4623. procedure cdicont(idolfiles)
  4624.   if comp = -2 then return  # -t --> don't icont at all
  4625.   args := " -c"
  4626.   rms  := ""
  4627.   every ifile := !idolfiles do args ||:= " " || ifile
  4628.   every ifile := !idolfiles do rms  ||:= " " || ifile || ".icn"
  4629.  
  4630.   every ifile := !idolfiles do mysystem("@vms "||ifile||".icn")
  4631. end
  4632.  
  4633. procedure sysinitialize()
  4634.     lnkopt := " \"-Sr500\" \"-Si1000\" \"-SF30\" \"-Sg500\" "
  4635.     cd    := "set default "
  4636.     md    := "create/dir "
  4637.     env   := "[.idolenv]"
  4638.     sysok    := 1
  4639. end
  4640. ##########
  4641. warntest.iol
  4642. # This is a test of the emergency broadcasting system.
  4643. # This is only a test.
  4644.  
  4645. class a ( field )
  4646. end
  4647.  
  4648. class b : a ( field )
  4649. end
  4650.