Commit da52aaef authored by Bas Lijnse's avatar Bas Lijnse

Import of Pieter's latest version

parents
definition module ESMSpec
import StdClass, StdMaybe
import gast //gen
:: Traces s i o :== [[SeenTrans s i o]]
:: ESM s i o = { s_0 :: s // the initial state
, d_F :: Spec s i o // the state transition function (\delta_F)
, out :: s i -> [[o]] // outputs to be used if spec does not give them
, pred :: (SeenTrans s i o)->[[String]] // consitency issues
, esm_name :: String
}
:: KnownAutomaton s i o = {trans :: [SeenTrans s i o]
,issues:: [(SeenTrans s i o,[String])]
}
:: SeenTrans s i o :== (s,i,[o],s)
tupToSpec :: (state input -> [([output],state)]) -> Spec state input output // conversion for old specificaions
class render a :: !a -> String // show a concise text representation for rendering purposes
class renderEq a | render a & gEq{|*|} a
enumerate :: [a] | ggen{|*|} a
possibleInputs :: (ESM s i o) [s] -> [i] | gEq{|*|} s & ggen{|*|}, gEq{|*|} i
nextStates :: (ESM s i o) i ![s] -> [s] | gEq{|*|} s
addStep :: (ESM s i o) [s] i !(Traces s i o) -> Traces s i o | gEq{|*|} s
narrowTraces :: (Traces s i o) [s] -> Traces s i o | gEq{|*|} s
nodesOf :: !(KnownAutomaton s i o) -> [s] | gEq{|*|} s
sharedNodesOf :: !(KnownAutomaton s i o) -> [s] | gEq{|*|}, Eq s
edgesFrom :: s !(KnownAutomaton s i o) -> [SeenTrans s i o] | gEq{|*|} s
edgesTo :: s !(KnownAutomaton s i o) -> [SeenTrans s i o] | gEq{|*|} s
startStates :: ![SeenTrans s i o] -> [s] | gEq{|*|} s
targetStates :: ![SeenTrans s i o] -> [s] | gEq{|*|} s
//addTransitions :: !Int (ESM s i o) [s] [i] !(KnownAutomaton s i o) -> KnownAutomaton s i o | gEq{|*|}, render s & render, ggen{|*|}, gEq{|*|} i & gEq{|*|} o
addTransitions :: !Int (ESM s i o) [s] [i] !(KnownAutomaton s i o) -> KnownAutomaton s i o | render, gEq{|*|} s & render, gEq{|*|}, ggen{|*|} i & gEq{|*|} o
nrOf :: !(KnownAutomaton s i o) s -> Int | gEq{|*|}, render s
gisMember :: a ![a] -> Bool | gEq{|*|} a
gremoveDup :: !.[a] -> .[a] | gEq{|*|} a
gelemIndex :: a ![a] -> Maybe Int | gEq{|*|} a
implementation module ESMSpec
import StdBool, StdList, StdMaybe, StdMisc, StdString, StdTuple, StdOrdList
import GenPrint, GenEq, Data.List
import gast
tupToSpec :: (state input -> [([output],state)]) -> Spec state input output // conversion for old specificaions
tupToSpec fun = \s i = [Pt o t \\ (o,t) <- fun s i]
enumerate :: [a] | ggen{|*|} a
enumerate = take 100 (generateAll aStream)
possibleInputs :: (ESM s i o) [s] -> [i] | gEq{|*|} s & ggen{|*|}, gEq{|*|} i
possibleInputs esm states = gremoveDup (take 100 [i \\ s<-states, i<-enumerate | not (isEmpty (esm.d_F s i))])
nextStates :: (ESM s i o) i ![s] -> [s] | gEq{|*|} s
nextStates esm i states
= gremoveDup [ t
\\ s <- states
, target <- esm.d_F s i
, t <- case target of
Pt outs u = [u];
Ft f = [u \\ o<-esm.out s i, u<-f o]
]
narrowTraces :: (Traces s i o) [s] -> Traces s i o | gEq{|*|} s
narrowTraces trace states = fst (pruneTraces trace states)
pruneTraces :: (Traces s i o) [s] -> (Traces s i o,[s]) | gEq{|*|} s
pruneTraces [] states = ([],states)
pruneTraces [trans:rest] states
# (rest ,states) = pruneTraces rest states
# trans = [tr \\ tr=:(s,i,o,t) <- trans | gisMember t states]
= ([trans:rest],startStates trans)
addStep :: (ESM s i o) [s] i !(Traces s i o) -> Traces s i o | gEq{|*|} s
addStep esm states i trace
= narrowTraces trace states ++
[[ (s,i,o,t)
\\ s <- states
, target <- esm.d_F s i
, (o,t) <- case target of
Pt outs u = [(outs,u)];
Ft f = [ (o,u) \\ o<-esm.out s i, u<-f o]
]]
nodesOf :: !(KnownAutomaton s i o) -> [s] | gEq{|*|} s
//nodesOf automaton = gremoveDup (flatten [[startnode,endnode] \\ (startnode,_,_,endnode) <- automaton.trans])
nodesOf automaton = gremoveDup ([s \\ (s,_,_,t) <- automaton.trans]++[t \\ (s,_,_,t) <- automaton.trans])
sharedNodesOf :: !(KnownAutomaton s i o) -> [s] | gEq{|*|}, Eq s
sharedNodesOf automaton
= [ n \\ n <- nodes, m <- nodes | n<>m && n === m ]
where nodes = removeDup ([s \\ (s,_,_,t) <- automaton.trans]++[t \\ (s,_,_,t) <- automaton.trans])
edgesFrom :: s !(KnownAutomaton s i o) -> [SeenTrans s i o] | gEq{|*|} s
edgesFrom startnode automaton = [edge \\ edge=:(s,i,o,t) <- automaton.trans | s===startnode]
edgesTo :: s !(KnownAutomaton s i o) -> [SeenTrans s i o] | gEq{|*|} s
edgesTo endnode automaton = [edge \\ edge=:(s,i,o,t) <- automaton.trans | t===endnode]
startStates :: ![SeenTrans s i o] -> [s] | gEq{|*|} s
startStates transitions = gremoveDup [ s \\ (s,i,o,t) <- transitions ]
targetStates :: ![SeenTrans s i o] -> [s] | gEq{|*|} s
targetStates transitions = gremoveDup [ t \\ (s,i,o,t) <- transitions ]
addTransitions :: !Int (ESM s i o) [s] [i] !(KnownAutomaton s i o) -> KnownAutomaton s i o | render, gEq{|*|} s & render, gEq{|*|}, ggen{|*|} i & gEq{|*|} o
addTransitions n esm startstates is automaton
| n>0 && not (isEmpty startstates)
# newSeenTrans
= [ (s,i,o,t)
\\ s <- startstates
, i <- map snd (sortBy (\(a,_) (b,_).a<b) (map (\i.(render i,i)) is)) // is // sort inputs
, target <- esm.d_F s i
, (o,t) <- case target of
Pt outs u = [(outs,u)];
Ft f = [ (o,u) \\ o<-esm.out s i, u<-f o]
]
# newStates = targetStates newSeenTrans
# newTrans = [t \\ t <- newSeenTrans | not (gisMember t automaton.trans)]
# newIssues = [(t,e) \\ t<-newTrans, e <- esm.pred t | not (isEmpty e)]
= addTransitions (n-1) esm newStates (possibleInputs esm newStates) {trans=mix automaton.trans newTrans, issues=newIssues++automaton.issues}
| otherwise = automaton
mix :: [SeenTrans s i o] [SeenTrans s i o] -> [SeenTrans s i o] | render s & render i
mix known new = foldl (insertBy less) known new
insertBy :: (a a->Bool) [a] a -> [a]
insertBy le [] e = [e]
insertBy le l=:[a:x] e
| le e a
= [e:l]
= [a:insertBy le x e]
less :: (SeenTrans s i o) (SeenTrans s i o) -> Bool | render s & render i
less (s1,i1,o1,t1) (s2,i2,o2,t2)
# rs1 = render s1
# rs2 = render s2
# ro1 = render i1
# ro2 = render i2
# rt1 = render t1
# rt2 = render t2
= rs1<rs2 || (rs1==rs2 && (ro1<ro2 || (ro1==ro2 && rt1<=rt2)))
nrOf :: !(KnownAutomaton s i o) s -> Int | gEq{|*|}, render s
nrOf automaton s
= case gelemIndex s (nodesOf automaton) of
Just i = i
nothing = abort ("nrOf applied to unknown state: "+++render s+++"\n")
gisMember :: a ![a] -> Bool | gEq{|*|} a
gisMember x [hd:tl] = hd===x || gisMember x tl
gisMember _ _ = False
gremoveDup :: !.[a] -> .[a] | gEq{|*|} a
gremoveDup [x:xs] = [x:gremoveDup (filter ((=!=) x) xs)]
gremoveDup _ = []
gelemIndex :: a ![a] -> Maybe Int | gEq{|*|} a
gelemIndex x l = scan 0 x l
where
scan i x [a:r]
| x===a = Just i
= scan (i+1) x r
scan i x _ = Nothing
definition module ESMVizTool
import ESMSpec
import iTasks
class all a | iTask, render, gEq{|*|} a
/*
esmVizTool :: !(ESM s i o) *HSt -> ((Bool,String),Html,*HSt)
| iData, gEq{|*|}, render s
& iData, gEq{|*|}, render, ggen{|*|} i
& iData, gEq{|*|}, render o
*/
//esmVizTool :: !(ESM s i o) *World -> *World | iTask, gEq{|*|}, render, Eq s & iTask, gEq{|*|}, render, ggen{|*|} i & iTask, gEq{|*|}, render o
//esmVizTool :: !(ESM s i o) *World -> *World | iTask, renderEq s & iTask, renderEq, Eq, ggen{|*|} i & iTask, gEq{|*|}, render o
esmVizTool :: !(ESM s i o) *World -> *World
// | iTask, render, gEq{|*|}, Eq s & iTask, render, gEq{|*|}, ggen{|*|} i & iTask, gEq{|*|}, render o
| all, Eq, genShow{|*|} s & all, genShow{|*|}, ggen{|*|} i & all o
toHtmlString :: a -> String | gText{|*|} a
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
definition module GraphvizVisualization
/** This module provides the iTasks class for the Graphviz library
**/
import Data.Graphviz, iTasks
derive gText Digraph
derive gUpdate Digraph
derive gVerify Digraph
derive JSONEncode Digraph
derive JSONDecode Digraph
derive gEq Digraph
derive gEditor Digraph
derive gEditMeta Digraph
derive gDefault Digraph
This diff is collapsed.
definition module confSM
/*
GAST: A Generic Automatic Software Test-system
ioco: Input Output COnformance of reactive systems
Pieter Koopman, 2004-2008
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import StdFile
import Math.Random, gen,/* genLibTest,*/ testable, StdMaybe
:: Spec state input output :== state input -> [Trans output state]
:: Trans output state = Pt [output] state | Ft ([output]->[state])
derive genShow Trans
:: IUTstep t i o :== t -> .(i -> .([o],t))
SpectoIUTstep :: (Spec t i o) (t i -> [[o]]) -> IUTstep (t,RandomStream) i o | genShow{|*|} t & genShow{|*|} i & genShow{|*|} o
toSpec :: (state input -> [(state,[output])]) -> Spec state input output
genLongInputs :: s (Spec s i o) [i] Int [Int] -> [[i]]
generateFSMpaths :: s (Spec s i o) [i] (s->[i]) -> [[i]] | gEq{|*|} s
:: TestOption s i o
= Ntests Int
| Nsequences Int
| Seed Int
| Randoms [Int]
| FixedInputs [[i]]
| InputFun (RandomStream s -> [i])
| OnPath Int
// | OutputFun ([s] i -> o)
| FSM [i] (s->[i]) // inputs state_identification
| MkTrace Bool
| OnTheFly
| SwitchSpec (Spec s i o)
| OnAndOffPath
| ErrorFile String
| TStop ([s] -> Bool)
| Inconsistent ([o] [s] -> Maybe [String])
testConfSM :: [TestOption s i o] (Spec s i o) s (IUTstep .t i o) .t (.t->.t) *d -> (.t,*d)
| FileSystem d & ggen{|*|} i & gEq{|*|} s & gEq{|*|} o & genShow{|*|} s & genShow{|*|} i & genShow{|*|} o
//testConfSM :: [TestOption s i o] (Spec s i o) s (IUTstep .t i o) .t (.t->.t) *File *File -> (.t,*File,*File)
// | ggen{|*|} i & gEq{|*|} s & gEq{|*|} o & genShow{|*|} s & genShow{|*|} i & genShow{|*|} o
(after) infix 0 :: [s] (Spec s i o) -> ([i] -> [s])
propDeterministic :: (Spec s i o) s i -> Bool
propTotal :: (Spec s i o) s i -> Bool
//propComplete :: (Spec s i o) s i -> Bool // equal to propTotal
propComplete spec s i :== propTotal spec s i
This diff is collapsed.
definition module gast
/*
GAST: A Generic Automatic Software Test-system
Pieter Koopman, 2004-2008
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import Math.Random, gen, GenEq, genLibTest, testable, confSM, stdProperty
implementation module gast
/*
GAST: A Generic Automatic Software Test-system
Pieter Koopman, 2004
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
\ No newline at end of file
definition module gen
/*
GAST: A Generic Automatic Software Test-system
gen: generic generation of values of a type
Pieter Koopman, 2004
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import StdGeneric
randomize :: [a] [Int] Int ([Int] -> [a]) -> [a]
generic ggen a :: Int [Int] -> [a]
derive ggen Int, Bool, Real, Char, UNIT, PAIR, EITHER, CONS, OBJECT, FIELD, (,), (,,), (,,,), [], String
maxint :: Int
minint :: Int
StrLen :== 80
implementation module gen
/*
GAST: A Generic Automatic Software Test-system
gen: generic generation of values of a type
Pieter Koopman, 2004
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import StdGeneric, Math.Random
import StdBool, StdList, StdArray, StdEnum, StdMisc
from StdFunc import id, seqList, :: St
// -------
:: RandomStream :== [Int]
aStream :: RandomStream
aStream = genRandInt 42
split :: RandomStream -> (RandomStream,RandomStream)
split [r,s:rnd]
# seed = r*s
| seed==0
= split rnd
= (genRandInt seed, rnd)
split _ = abort "gen.icl: the increadable has been done, you have used all random values!"
// -------
randomize :: [a] [Int] Int ([Int] -> [a]) -> [a]
randomize list rnd n c = rand list rnd n []
where
rand [] rnd m [] = c rnd
rand [] rnd m [x] = [x:c rnd]
rand [] rnd m l = rand l rnd n []
rand [a:x] [i:rnd] m l
| m==0 || (i rem m) == 0
= [a:rand x rnd (m-1) l]
= rand x rnd m [a:l]
// -------
generic ggen a :: Int [Int] -> [a]
maxint :: Int
maxint = 2147483647
minint :: Int
minint = -2147483648
ggen{|Int|} n rnd = randomize [0,1,-1,maxint,minint] rnd 5 id
ggen{|Bool|} n rnd = randomize [False,True] rnd 2 \_.[]
ggen{|Char|} n rnd = randomize (map toChar [32..126] ++ ['\t\n\r']) rnd 98 (\_.[])
ggen{|Real|} n rnd = randomize [0.0,1.0,-1.0] rnd 3 (\[s:x] -> f x (genRandReal s))
where f [i,j:x] [r:s]
| r==0.0
= [r:f x s]
# r = if (isOdd i) r (~r)
r = if (isOdd j) r (1.0/r)
= [r:f x s]
bias :== 1024
ggen{|UNIT|} n rnd = [UNIT]
ggen{|PAIR|} f g n rnd
# (rn2,rnd) = split rnd
= map (\(a,b)=PAIR a b) (diag2 (f n rnd) (g n rn2)) // inlinen !?
ggen{|EITHER|} f g n rnd
# (r1,rnd) = split rnd
(r2,rnd) = split rnd
= Merge n rnd (f n r1) (g (n+1) r2)
where
Merge :: Int RandomStream [a] [b] -> [EITHER a b] // Correct, strict in none of the lists!
Merge n [i:r] as bs
| (i rem n) <> 0
// | (i rem bias) > n+(bias/2)
= case as of
[] = map RIGHT bs
[a:as] = [LEFT a: Merge n r as bs]
= case bs of
[] = map LEFT as
[b:bs] = [RIGHT b: Merge n r as bs]
/* Merge :: RandomStream [a] [b] -> [EITHER a b] // Wrong, strict in both lists
Merge r [] bs = map RIGHT bs
Merge r as [] = map LEFT as
Merge [i:r] [a:as] [b:bs]
| isOdd i
= [LEFT a, RIGHT b:Merge r as bs]
= [RIGHT b, LEFT a:Merge r as bs]
*//* = Merge (isOdd (hd rnd)) (f r1) (g r2)
where
Merge :: Bool [a] [b] -> [EITHER a b]
Merge r as bs
| r
= case as of
[] = map RIGHT bs
[a:as] = [LEFT a: Merge (not r) as bs]
= case bs of
[] = map LEFT as
[b:bs] = [RIGHT b: Merge (not r) as bs]
*/
ggen{|CONS|} f n rnd = map CONS (f n rnd)
ggen{|OBJECT|} f n rnd = map OBJECT (f n rnd)
ggen{|FIELD|} f n rnd = map FIELD (f n rnd)
ggen{|String|} n rnd = ["hello world!","Tested with GAST!": rndStrings 0 rnd]
where
rndStrings 0 rnd = ["": rndStrings 1 rnd]
rndStrings len [r,s:rnd]
# (chars,rnd) = seqList (repeatn ((abs r) rem len) genElem) rnd
string = {c \\ c<-chars}
= [string:rndStrings ((len rem StrLen)+1) rnd]
class genElem a where genElem :: RandomStream -> .(a,RandomStream)
instance genElem Int where genElem [r:rnd] = (r,rnd)
instance genElem Char where genElem [r:rnd] = (toChar (32+((abs r) rem 94)),rnd)
instance genElem Bool where genElem [r:rnd] = (isOdd r,rnd)
instance genElem Real where genElem [r,s,t:rnd] = ((toReal r/toReal s)*toReal t,rnd)
derive ggen (,), (,,), (,,,), []
derive bimap []
definition module genLibTest
/*
GAST: A Generic Automatic Software Test-system
genLibtest: library for generic testing: showing and comparing values
Pieter Koopman, 2004
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import StdGeneric, GenEq
import StdClass
instance + String
(@@) infixl 2 :: (a->b) a -> b
(@@!)infixl 2 :: (a->b) !a -> b
generic genShow a :: String Bool a [String] -> [String]
generic gLess a :: a a -> Bool
derive genShow Int, Char, Bool, Real, String, UNIT, PAIR, EITHER, OBJECT, CONS of {gcd_name,gcd_arity},RECORD of {grd_name}, FIELD of {gfd_name}, [], (,), (,,), (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,), (,,,,,,,,), (,,,,,,,,,), (->), {}, {!}
derive gLess Int, Char, Bool, Real, String, UNIT, PAIR, EITHER, OBJECT, CONS, FIELD, [], (,), (,,), (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,), (,,,,,,,,), (,,,,,,,,,)
show :: !a -> [String] | genShow{|*|} a
show1 :: !a -> String | genShow{|*|} a
(-<-) infix 4 :: !a !a -> Bool | gLess{|*|} a
(->-) infix 4 :: !a !a -> Bool | gLess{|*|} a
(-<=) infix 4 :: !a !a -> Bool | gLess{|*|} a
(=>-) infix 4 :: !a !a -> Bool | gLess{|*|} a
implementation module genLibTest
/*
GAST: A Generic Automatic Software Test-system
genLibtest: library for generic testing: showing and comparing values
Pieter Koopman, 2004
Radboud Universty, Nijmegen
The Netherlands
pieter@cs.ru.nl
*/
import StdEnv, StdGeneric, GenEq
instance + String where (+) s t = s +++ t
(@@)infixl 2 :: (a->b) a -> b
(@@) f x = f x
(@@!)infixl 2 :: (a->b) !a -> b
(@@!) f x = f x
//--- show ---//
generic genShow a :: String Bool a [String] -> [String]
genShow{|Int|} sep p x rest = [toString x: rest]
genShow{|Char|} sep p x rest = ["'",showChar x,"'": rest]
genShow{|Bool|} sep p x rest = [toString x: rest]
genShow{|Real|} sep p x rest = [toString x: rest]
genShow{|String|} sep p s rest = ["\"",s,"\"":rest]
genShow{|UNIT|} sep p _ rest = rest
genShow{|PAIR|} fx fy sep p (PAIR x y) rest
// | p
// = ["(":fx sep p x [sep: fy sep p y [")":rest]]]
= fx sep p x [sep: fy sep p y rest]
//genShow{|PAIR|} fx fy sep p (PAIR x y) rest = fx sep True x [sep: fy sep True y rest]
genShow{|EITHER|} fl fr sep p (LEFT x) rest = fl sep p x rest
genShow{|EITHER|} fl fr sep p (RIGHT x) rest = fr sep p x rest
genShow{|OBJECT|} f sep p (OBJECT x) rest = f sep p x rest
genShow{|(->)|} fa fr sep p f rest = ["<function>": rest]
genShow{|{}|} fx sep p xs rest = ["{" :showList fx [x\\x<-:xs] ["}":rest]]
genShow{|{!}|} fx sep p xs rest = ["{!":showList fx [x\\x<-:xs] ["}":rest]]
//genShow{|{#}|} fx sep p xs rest = ["{#":showList fx [x\\x<-:xs] ["}":rest]]
genShow{|[]|} f sep p xs rest = ["[" :showList f xs ["]":rest]]
genShow{|(,)|} f1 f2 sep p (x1,x2) rest = ["(":f1 sep False x1 [",":f2 sep False x2 [")":rest]]]
genShow{|(,,)|} f1 f2 f3 sep p (x1,x2,x3) rest = ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [")":rest]]]]
genShow{|(,,,)|} f1 f2 f3 f4 sep p (x1,x2,x3,x4) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [")":rest]]]]]
genShow{|(,,,,)|} f1 f2 f3 f4 f5 sep p (x1,x2,x3,x4,x5) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [")":rest]]]]]]
genShow{|(,,,,,)|} f1 f2 f3 f4 f5 f6 sep p (x1,x2,x3,x4,x5, x6) rest = ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [",":f6 sep False x6 [")":rest]]]]]]]
genShow{|(,,,,,,)|}f1 f2 f3 f4 f5 f6 f7 sep p (x1,x2,x3,x4,x5,x6,x7) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [",":f6 sep False x6 [",":f7 sep False x7 [")":rest]]]]]]]]
genShow{|(,,,,,,,)|}f1 f2 f3 f4 f5 f6 f7 f8 sep p (x1,x2,x3,x4,x5,x6,x7,x8) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [",":f6 sep False x6 [",":f7 sep False x7 [",":f8 sep False x8 [")":rest]]]]]]]]]
genShow{|(,,,,,,,,)|}f1 f2 f3 f4 f5 f6 f7 f8 f9 sep p (x1,x2,x3,x4,x5,x6,x7,x8,x9) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [",":f6 sep False x6 [",":f7 sep False x7 [",":f8 sep False x8 [",":f9 sep False x9 [")":rest]]]]]]]]]]
genShow{|(,,,,,,,,,)|}f1 f2 f3 f4 f5 f6 f7 f8 f9 f0 sep p (x1,x2,x3,x4,x5,x6,x7,x8,x9,x0) rest
= ["(":f1 sep False x1 [",":f2 sep False x2 [",":f3 sep False x3 [",":f4 sep False x4 [",":f5 sep False x5 [",":f6 sep False x6 [",":f7 sep False x7 [",":f8 sep False x8 [",":f9 sep False x9 [",":f0 sep False x0 [")":rest]]]]]]]]]]]
genShow{|CONS of {gcd_name, gcd_arity}|} fx sep p (CONS x) rest
| gcd_arity == 0
= [gcd_name: rest]
| otherwise
| p // parentheses needed
// = ["(",gcd_name," ":fx " " False x [")":rest]]
// = [gcd_name," ":fx " " False x rest]
= ["(",gcd_name," ":fx " " True x [")":rest]]
= [gcd_name," ":fx " " True x rest]
genShow{|RECORD of {grd_name}|} fx sep p (RECORD x) rest
= ["{",{grd_name.[i]\\i<-[1..size grd_name-1]},"|":fx "," False x ["}":rest]]