;;; -*- logo -*- ;;; ;;; .logo -- Logo initialization file (v.0.9.0) Hrvoje Blazevic ;;; ;; Reversing 5.1 changes ;; Don't like getter/setter syntax "simplification". .LOOPS is ;; slow even without ALLOWGETSET. UNBURYONEDIT is meaningless ;; in logo-mode, and can possibly get in the way. make "state.allowgetset :allowgetset make "state.unburyonedit :unburyonedit bury [[] [state.allowgetset state.unburyonedit] []] erase [[] [allowgetset unburyonedit] []] pr [ALLOWGETSET and UNBURYONEDIT disabled] type "|loading LOOPS ... | wait 0 ;; Allowing changes to Logo primitives make "redefp "true ;; Preserving original definitions copydef "if.tf "if copydef "ifelse.tf "ifelse copydef "not.tf "not copydef "and.tf "and copydef "or.tf "or copydef "test.tf "test ;; Freeing names erase [if ifelse not and or test] ;;; New definitions .macro if :tf.val :run.true [:run.false []] 2 op (if.tf equalp :tf.val "false [:run.false] [:run.true]) end .macro ifelse :tf.val :run.true :run.false op (if.tf equalp :tf.val "false [:run.false] [:run.true]) end to not :thing.not op (if.tf equalp :thing.not "false ["true] ["false]) end to true op "true end to false op "false end copydef "else "true copydef "t "true to and [:form.and ["true]] [:forms.and] 2 if.tf emptyp :forms.and [op run :form.and] if run :form.and [op apply "and :forms.and] op "false end to or [:form.or ["false]] [:forms.or] 2 if.tf emptyp :forms.or [op run :form.or] cond.if run :form.or op apply "or :forms.or end .macro cond.if :#cond.val if :#cond.val [op list "op :#cond.val] op [] end to .and [:form.and ["true]] [:forms.and] 2 if.tf emptyp :forms.and [op first lput "#unspecified runresult :form.and] if.tf not first lput "#unspecified runresult :form.and [op "false] op apply ".and :forms.and end .macro test :any.value op (list "test.tf "not.tf "not quoted :any.value) end ;;; Extended prefix operators copydef "difference.s "difference copydef "quotient.s "quotient erase [difference quotient equal? greater? less? before?] to difference :first.num [:rest.nums] 2 if.tf emptyp :rest.nums [op minus :first.num] op :first.num - (apply "sum :rest.nums) end to quotient :first.num [:rest.nums] 2 if.tf emptyp :rest.nums [op (1 / :first.num)] op :first.num / (apply "product :rest.nums) end to equal? :elt [:rest] 2 op emptyp find [not.tf equalp ? :elt] :rest end to less? :elt [:nums] 2 if.tf emptyp :nums [op "true] if.tf :elt < first :nums [op apply "less? :nums] op "false end to greater? :elt [:nums] 2 if.tf emptyp :nums [op "true] if.tf greaterp :elt first :nums [op apply "greater? :nums] op "false end to before? :wd [:wds] 2 if.tf emptyp :wds [op "true] if.tf beforep :wd first :wds [op apply "before? :wds] op "false end to lesseq? :elt [:nums] 2 if.tf emptyp :nums [op "true] if.tf :elt > first :nums [op "false] op apply "lesseq? :nums end to greatereq? :elt [:nums] 2 if.tf emptyp :nums [op "true] if.tf lessp :elt first :nums [op "false] op apply "greatereq? :nums end to beforeq? :wd [:wds] 2 if.tf emptyp :wds [op "true] if.tf beforep first :wds :wd [op "false] op apply "beforeq? :wds end ;;; Cleaning up ;; Prohibit further changes of primitives ern "redefp bury [if ifelse not true false else or and .and test cond.if] bury [difference equal? greater? less? greatereq? lesseq? beforeq? quotient before? difference.s quotient.s] ;;; Defining High Level Structures ;;; Letrec .macro letrec :in.letrec local [body.letrec method.&stack] make "method.&stack [] make "body.letrec fput "dummy.letrec (list fput [] bf :in.letrec) op insert.invoke letrec.helper lput :body.letrec first :in.letrec end to letrec.helper :clauses.letrec if.tf emptyp :clauses.letrec [op (list "run [(dummy.letrec)])] push "method.&stack first first :clauses.letrec op (se "local (word "" first :method.&stack) "make (word "" first :method.&stack) bf first :clauses.letrec letrec.helper bf :clauses.letrec) end to insert.invoke :text if.tf emptyp :text [op []] if.tf wordp first :text [ op (or [(and [equalp first :text "\(] [memberp first bf :text :method.&stack] [(se first :text "invoke word ": first bf :text insert.invoke bf bf :text)])] [se first :text insert.invoke bf :text])] op (if.tf listp first :text [fput insert.invoke runparse first :text insert.invoke bf :text] [fput first :text insert.invoke bf :text]) end ;;; Cond -- 2 versions ;; universal -- operation and command .macro cond.ifelse :#cond.val :#cond.rest op ifelse :#cond.val [(list :#cond.val)] [:#cond.rest] end .macro cond :cond.clauses local [fclauses lclause] make "lclause last :cond.clauses (if.tf and [wordp first :lclause] [memberp first :lclause [else true t]] [make "lclause apply "se bf :lclause make "fclauses bl :cond.clauses] [make "fclauses :cond.clauses make "lclause ["#unspecified]]) op cond.helper :fclauses end to cond.helper :cond.clauses if.tf emptyp :cond.clauses [op :lclause] if.tf emptyp bf first :cond.clauses [ op (se "cond.ifelse first first :cond.clauses (list cond.helper bf :cond.clauses))] op (se "ifelse.tf first first :cond.clauses (list apply "se bf first :cond.clauses) (list cond.helper bf :cond.clauses)) end ;; command only -- slightly faster .macro condc :cond.clauses local [fclauses lclause] make "lclause last :cond.clauses (if.tf and [wordp first :lclause] [memberp first :lclause [else true t]] [make "lclause apply "se bf :lclause make "fclauses bl :cond.clauses] [make "fclauses :cond.clauses make "lclause ["#unspecified]]) op condc.helper :fclauses end to condc.helper :cond.clauses if.tf emptyp :cond.clauses [op :lclause] if.tf emptyp bf first :cond.clauses [ op (se "cond.if first first :cond.clauses condc.helper bf :cond.clauses)] op (se "if.tf first first :cond.clauses (list apply "se bf first :cond.clauses) condc.helper bf :cond.clauses) end ;;; Case ;; universal -- operation and command, but *must* output a value .macro case :case.clauses local [fclauses lclause] make "lclause last :case.clauses (if.tf and [wordp first :lclause] [memberp first :lclause [else true t]] [make "lclause apply "se bf :lclause make "fclauses bl bf :case.clauses] [make "fclauses bf :case.clauses make "lclause ["#unspecified]]) op (se (list "local ""#target "make ""#target "run first :case.clauses) case.helper :fclauses) end to case.helper :first.clauses if.tf emptyp :first.clauses [op :lclause] op (se "ifelse.tf "memberp ":#target (list first first :first.clauses) (list apply "se bf first :first.clauses) (list case.helper bf :first.clauses)) end ;;; casec ;; command only -- mix code, true forms do not have to output .macro casec :case.clauses local [fclauses lclause] make "lclause last :case.clauses (if.tf and [wordp first :lclause] [memberp first :lclause [else true t]] [make "lclause apply "se lput [op "#unspecified] bf :lclause make "fclauses bl bf :case.clauses] [make "fclauses bf :case.clauses make "lclause [op "#unspecified]]) op (se (list "local ""#target "make ""#target "run first :case.clauses) casec.helper :fclauses) end to casec.helper :first.clauses if.tf emptyp :first.clauses [op :lclause] op (se "ifelse.tf "memberp ":#target (list first first :first.clauses) (list apply "se lput [op "#unspecified] bf first :first.clauses) (list casec.helper bf :first.clauses)) end ;;; Compiler -- source is commented out. Only the compiled code gets loaded. ; to loops.compiler [:proc procedures] 1 ; letrec [[ ; [compile.proc [[proc] ; [if emptyp :proc [op []]] ; [local "struct.min] ; [op ifelse.tf ; (and [wordp first :proc] ; [macrop first :proc] ; [not gprop "compiler.cap first :proc] ; [not.tf emptyp bf :proc] ; [listp first bf :proc]) ; [make "compiled "true ; se (list "run macroexpand list first :proc ; (compile.proc first bf :proc)) ; (compile.proc bf bf :proc)] ; [or [and [listp first :proc] ; [fput (compile.proc first :proc) ; (compile.proc bf :proc)]] ; [fput first :proc (compile.proc bf :proc)]]]]] ; [compile.ws [[proc.lst compiled] ; [if.tf emptyp :proc.lst [stop]] ; [.type (se "compiling first :proc.lst "|... |)] ; [wait 0] ; [(invoke (or [and [macrop first :proc.lst] ; [".defmacro]] ; ["define]) ; first :proc.lst (compile.proc text first :proc.lst))] ; [.pr (if.tf :compiled ; [.and [pprop "compiled.procs first :proc.lst "true] ; ["OK]] ; [(se [nothing to do for] first :proc.lst)])] ; [(compile.ws bf :proc.lst "false)]]]] ; [ifelse listp :proc [(compile.ws filter "procedurep :proc "false)] ; [(compile.ws filter "procedurep (list :proc) "false)]] ; [.pr [compilation completed]]] ; end ;;; Invoking the compiler from logo-mode with Compile Workspace ;; ;; Using ws.compile instead of loops.compiler ;; Filtering out all procedure names that end with .class ;; Compiling Class templates, firstly makes no sense, secondly, ;; will make Class unusable to the OBJECT.MAKER ;; ;;; ws.compile to ws.compile local "split (loops.compiler filter [[x] [make "split split.word :x ". op not (and [1 < count :split] [equalp last :split "class])]] procedures) end to compile.object :text if.tf emptyp :text [op []] if.tf (and [wordp first :text] [macrop first :text] [not gprop "compiler.cap first :text] [not.tf emptyp bf :text] [listp first bf :text]) ~ [op se (list "run macroexpand list first :text compile.object first bf :text) compile.object bf bf :text] if.tf listp first :text ~ [op fput compile.object first :text compile.object bf :text] op fput first :text compile.object bf :text end to .type :text if.tf :.verbose [type :text] end to .pr :text if.tf :.verbose [pr :text] end ;; specifying compiler output make ".verbose "true ;; Saving *only* compiled procedures. to save.compiled [:filename .and [type "|Enter file name to save to: |] [rw]] 1 if.tf namep "printwidthlimit ~ [localmake "width :printwidthlimit ern "printwidthlimit] if.tf namep "printdepthlimit ~ [localmake "depth :printdepthlimit ern "printdepthlimit] if equalp first :filename "" [make "filename bf :filename] local "oldwriter make "oldwriter writer openwrite :filename setwrite :filename po (filter [[proc] [op not.tf emptyp gprop "compiled.procs :proc]] procedures) setwrite :oldwriter close :filename if.tf namep "width [make "printwidthlimit :width] if.tf namep "depth [make "printdepthlimit :depth] end ;;; Compiler Capabilities ;;; ;;; Capabilities have this format: property = name of High Level Procedure ;;; value = "false ;;; ;;; You can add your own compiler capabilities, providing you follow ;;; these rules: High level procedure (structure) you define must have ;;; one input only - a list. And, of-course it must be a macro -- ;;; otherwise there is nothing for compiler to do. After you have ;;; defined (and tested) your procedure add your pprop line to lines ;;; below. That is all. pprop "compiler.cap "letrec "false pprop "compiler.cap "cond "false pprop "compiler.cap "condc "false pprop "compiler.cap "case "false pprop "compiler.cap "casec "false bury [[insert.invoke letrec letrec.helper cond cond.helper loops.compiler compile.object save.compiled case .pr case.helper casec casec.helper .type ws.compile condc condc.helper cond.ifelse] [.verbose] [compiler.cap compiled.procs]] ;;; End of interpreter changes (.logo) ;;; Additions to Logo library to before :first.wd [:rest.wds] 2 if emptyp :rest.wds [op :first.wd] if beforep first :rest.wds :first.wd [op apply "before :rest.wds] op apply "before fput :first.wd bf :rest.wds end to max :first [:rest] 2 if emptyp :rest [op :first] if greaterp :first first :rest [op apply "max fput :first bf :rest] op apply "max :rest end to min :first [:rest] 2 if emptyp :rest [op :first] if lessp :first first :rest [op apply "min fput :first bf :rest] op apply "min :rest end to evenp :number op zerop remainder :number 2 end copydef "even? "evenp to oddp :number op not evenp :number end copydef "odd? "oddp to zerop :number op equalp :number 0 end copydef "zero? "zerop to identity :stuff op :stuff end to last.pair :lst if emptyp bf :lst [op :lst] op last.pair bf :lst end to split.word :string [:delimiter "\ ] 2 local "result if emptyp :string [op (list ")] make "result split.word bf :string :delimiter if equalp first :string :delimiter [op fput " :result] op fput word first :string first :result bf :result end to time :instruction.list localmake "start first first shell [date "+%s"] pr runresult :instruction.list (pr "Elapsed "time: (first first shell [date "+%s"]) - :start "seconds) end .macro begin :begin.forms op apply "se :begin.forms end bury [before max min evenp even? oddp odd? zerop zero? identity last.pair split.word time begin] ;;; Restoring Standard Berkeley Logo ;;; This is of practical value only if used within Emacs logo-mode to restore.standard make "redefp "true copydef "if "if.tf copydef "ifelse "ifelse.tf copydef "not "not.tf copydef "and "and.tf copydef "or "or.tf copydef "test "test.tf copydef "difference "difference.s copydef "quotient "quotient.s copydef "equal? "equalp copydef "greater? "greaterp copydef "less? "lessp copydef "before? "beforep ;; .logo make "allowgetset :state.allowgetset make "unburyonedit :state.unburyonedit bury [[] [allowgetset unburyonedit] []] erase [ [if.tf ifelse.tf not.tf and.tf or.tf test.tf false else t true .and insert.invoke letrec letrec.helper cond cond.helper cond.if cond.ifelse condc condc.helper loops.compiler ws.compile save.compiled case case.helper difference.s quotient.s lesseq? greatereq? beforeq? .type .pr casec casec.helper begin] [.verbose state.allowgetset state.unburyonedit] [compiler.cap compiled.procs]] ;; loops erase [ [object.maker static.make compile.object bucket.class base.object counter.class send rewinding.counter.class container.class stack.class delegate #self border.class browse.classes circular.class double.end.class edit.classes indirect inherit inherit.from insert.method insert.tree inspect.methods.objects lambda list.class loops new objects.group pair.class queue.class save.image send.helper show.method.object static swap.pair.class word.class] [.accept.method loops.object.stack] [inheritance.tree]] ern "redefp gc ignore nodes gc ignore nodes gc pr [Standard Berkeley Logo restored.] end bury [restore.standard loops.compiler] ;;; Compiled code to loops.compiler [:proc procedures] 1 run [local "compile.proc make "compile.proc [[proc] [if emptyp :proc [op []]] [local "struct.min] [op ifelse.tf ( and [wordp first :proc] [macrop first :proc] [not gprop "compiler.cap first :proc] [not.tf emptyp bf :proc] [listp first bf :proc] ) [make "compiled "true se ( list "run macroexpand list first :proc ( invoke :compile.proc first bf :proc ) ) ( invoke :compile.proc bf bf :proc )] [or [and [listp first :proc] [fput ( invoke :compile.proc first :proc ) ( invoke :compile.proc bf :proc )]] [fput first :proc ( invoke :compile.proc bf :proc )]]]] local "compile.ws make "compile.ws [[proc.lst compiled] [if.tf emptyp :proc.lst [stop]] [.type ( se "compiling first :proc.lst "|... | )] [wait 0] [( invoke ( or [and [macrop first :proc.lst] [".defmacro]] ["define] ) first :proc.lst ( invoke :compile.proc text first :proc.lst ) )] [.pr ( if.tf :compiled [.and [pprop "compiled.procs first :proc.lst "true] ["OK]] [( se [nothing to do for] first :proc.lst )] )] [( invoke :compile.ws bf :proc.lst "false )]] local "dummy.letrec make "dummy.letrec [[] [ifelse listp :proc [( invoke :compile.ws filter "procedurep :proc "false )] [( invoke :compile.ws filter "procedurep ( list :proc ) "false )]] [.pr [compilation completed]]] run [( invoke :dummy.letrec )]] end type [Lisp layer OK ...] ;;; End of .logo