X-Received: by 2002:a0c:816c:: with SMTP id 99-v6mr2721108qvc.10.1524894021452; Fri, 27 Apr 2018 22:40:21 -0700 (PDT) X-Received: by 2002:a1f:c743:: with SMTP id x64-v6mr745713vkf.7.1524894021236; Fri, 27 Apr 2018 22:40:21 -0700 (PDT) Path: csiph.com!news.swapon.de!weretis.net!feeder6.news.weretis.net!feeder.usenetexpress.com!feeder-in1.iad1.usenetexpress.com!peer01.iad!feed-me.highwinds-media.com!news.highwinds-media.com!x25-v6no2562900qto.0!news-out.google.com!c8-v6ni252qtc.0!nntp.google.com!x25-v6no2562891qto.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.postscript Date: Fri, 27 Apr 2018 22:40:21 -0700 (PDT) Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=24.107.176.41; posting-account=G1KGwgkAAAAyw4z0LxHH0fja6wAbo7Cz NNTP-Posting-Host: 24.107.176.41 User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <7553e2f7-26c3-4fef-bc69-3c46a4e8b554@googlegroups.com> Subject: Structured Programming in PS From: luser droog Injection-Date: Sat, 28 Apr 2018 05:40:21 +0000 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Received-Bytes: 5999 X-Received-Body-CRC: 1151213883 Xref: csiph.com comp.lang.postscript:3256 I hope to kick off some fun with this nice inflammatory subject line. Revisiting the ideas from some recent posts, I decided to combine them all together into a mishmash. There are 3 layers or strata of definitions which supplement and/or depend upon the previous layer. But all three together enable the nice syntax illustrated in the final block. No multi-dispatch, but a nice syntax for typechecking arguments IMO. The first block defines the fundamental notion of 'pairs', ie. an executable array which is dumped and fed to <> to produce a dictionary. 'pairs-begin' does a 'begin' on this=20 dictionary, whereas 'pairs-def' instead iterates through and defines each pair in the current dictionary.=20 Any name which begins with @ is treated specially and executed=20 when encountered. You can see this with the @add in computing the value of 'var'. Since I'm not using dictionary-vs-array to determine what type of function to build, I chose to use strings for the more=20 complex definitions. This required a 'fortokens' control structure to iterate through the string contents. $ cat struct2.ps << /pairs-begin { pairs begin } /pairs-def { pairs {def} forall } /pairs { << exch explode >> } /explode { { @exec } forall } /@exec { dup type /nametype eq { exec-if-@ } if } /exec-if-@ { dup dup length string cvs dup first (@) first eq { exec@= }{ pop } ifelse } /exec@ { exch pop rest cvn cvx exec = } /first { 0 get } /rest { 1 1 index length 1 sub getinterval } >> begin=20 { block { pairs-begin main end } func { 1 index type /stringtype eq { typed-func }{ simple-func } ifels= e } simple-func { func-begin { end } compose } typed-func { exch args-and-types reverse /check-types load curry 3 1 r= oll exch simple-func /exec cvx 2 array astore cvx compose %p= stack()=3D } func-begin { exch reverse /args-begin load curry exch compose } args-begin { dup length dict begin { exch def } forall } args-and-types { /was_x false def [ exch { each-specifier } fortokens ] pairs dup keys exch values } each-specifier { dup xcheck /is_x exch def is_x was_x and { null exch = } if /was_x is_x def } check-types { % [ types ] dup length 1 add copy true exch { check-type and } forall exch pop = %pstack()=3D not { /user-function /typecheck signalerror } if } check-type { dup null eq { pop pop true }{ make-type-name 3 -1 roll type eq } ifelse } make-type-name { dup length 4 add string dup 3 1 roll dup 3 1 roll cvs 2 copy 0 exch putinterval length (type) putinterval cvn } keys { { pop } map } values { { exch pop } map } =20 map { 1 index xcheck 3 1 roll [ 3 1 roll forall ] exch {cvx} if } reduce { exch dup first exch rest 3 -1 roll forall } rreduce { exch aload length 1 sub dup 3 add -1 roll repeat } curry { [ 3 1 roll {} forall ] cvx } compose { 2 array astore cvx { {} forall } map } reverse { [ exch dup length 1 sub -1 0 { 2 copy get 3 1 roll pop } for = pop ] } var 2 3 @add } pairs-def { fortuple {a n p}{ 0 n /a load length 1 sub { /a exch /n getinterval /p exec } { load-if-literal-name } map end for } @func-begin load-if-literal-name { dup type /nametype eq 1 index xcheck not and { l= oad } if } fortokens {src proc}{ { src token { exch /src exch store }{ exit } ifelse proc } loop } @func } pairs-def { - sub + add * mul =20 f{x y z}{ x y z + * } @func g(x/integer y/integer){ x y + } @func =20 main { var =3D=3D [ 1 2 3 4 5 ] { - } rreduce =3D=3D 3 4 5 f =3D=3D 3 4 g =3D 3.0 4.0 g =3D quit } } block $ gsnd -q struct2.ps 5 3 27 7 Error: /typecheck in /user-function Operand stack: 3.0 4.0 Execution stack: %interp_exit .runexec2 --nostringval-- --nostringval-- --nostrin= gval-- 2 %stopped_push --nostringval-- --nostringval-- --nostring= val-- false 1 %stopped_push 2015 1 3 %oparray_pop 2014 1 = 3 %oparray_pop 1998 1 3 %oparray_pop 1884 1 3 %oparray_= pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --no= stringval-- --nostringval-- 2 %stopped_push --nostringval-- --nos= tringval-- --nostringval-- --nostringval-- Dictionary stack: --dict:984/1684(ro)(G)-- --dict:0/20(G)-- --dict:78/200(L)-- --dic= t:33/58(L)-- --dict:6/6(L)-- Current allocation mode is local Current file position is 2609 GPL Ghostscript 9.22: Unrecoverable error, exit code 1