reset a3, kut Charlie ;)
[tt2015.git] / a3 / code / Generics / GenPrint.icl
diff --git a/a3/code/Generics/GenPrint.icl b/a3/code/Generics/GenPrint.icl
new file mode 100644 (file)
index 0000000..d75f190
--- /dev/null
@@ -0,0 +1,306 @@
+implementation module GenPrint\r
+\r
+import StdGeneric, StdEnv, StdMaybe\r
+\r
+//-------------------------------------------------------------------------------------\r
+\r
+:: *StringOutput = {so_str :: !*String, so_pos :: !Int}\r
+\r
+\r
+instance PrintOutput StringOutput where\r
+       printOutput ch s=:{so_str, so_pos} \r
+               #! new_str = realloc_if_needed so_pos so_str \r
+               = {s & so_str = {new_str & [so_pos] = ch}, so_pos = inc so_pos}\r
+       where\r
+               realloc_if_needed :: Int u:String -> v:String, [u <= v]\r
+               realloc_if_needed pos str\r
+                       #! size_str = size str\r
+                       | pos == size_str\r
+                               #! new_str = createArray ((size_str + 1) * 3 /2) '\0'\r
+                               #! (new_str, str) = fill 0 size_str new_str str\r
+                               = new_str\r
+                       | otherwise     \r
+                               = str \r
+               fill i n new_str str \r
+                       | i == n\r
+                               = (new_str, str)\r
+                       | otherwise     \r
+                               #! (ch, str) = str![i] \r
+                               = fill (inc i) n {new_str & [i] = ch} str       \r
+                                       \r
+instance PrintOutput File where\r
+       printOutput x s\r
+               = fwritec x s\r
+\r
+\r
+//-------------------------------------------------------------------------------------\r
+\r
+\r
+($) infixl 9\r
+($) x y = y o x\r
+\r
+(@) infix 8 \r
+(@) x y = x y\r
+\r
+mapSt f [] st = ([], st)\r
+mapSt f [x:xs] st\r
+       # (y, st) = f x st\r
+       # (ys, st) = mapSt f xs st\r
+       = ([y:ys], st)\r
+\r
+foldSt f []            = id \r
+foldSt f [x:xs]        = foldSt f xs o f x\r
+\r
+//-------------------------------------------------------------------------------------\r
+:: PrintState s =\r
+       { ps_output :: !s\r
+       , ps_context :: !Context\r
+       }\r
+:: Context \r
+       = CtxNone                                                                               // initial env\r
+       | CtxNullary                                                                    // nullary constructor\r
+       | CtxRecord                                                                             // record constructor   \r
+       | CtxTuple                                                                              // tuple constructor\r
+       | CtxNonfix                                                                             // normal nonfix constructor\r
+       | CtxInfix                                                                              // infix constructor\r
+               String                                                                          // name\r
+               GenConsAssoc                                                            // constructor's associativity  \r
+               Prio                                                                            // constructors priority        \r
+               GenConsAssoc                                                            // left or right argument\r
+:: Prio :== Int\r
+       \r
+instance == GenConsAssoc where\r
+       (==) GenConsAssocNone GenConsAssocNone = True\r
+       (==) GenConsAssocLeft GenConsAssocLeft = True\r
+       (==) GenConsAssocRight GenConsAssocRight = True\r
+       (==) _ _ = False\r
+\r
+mkContext :: GenericConsDescriptor -> Context\r
+mkContext {gcd_prio=GenConsNoPrio, gcd_fields, gcd_name, gcd_arity}\r
+       | isEmpty gcd_fields \r
+               | gcd_arity == 0\r
+                       = CtxNullary\r
+               | is_tuple gcd_name\r
+                       = CtxTuple\r
+               | otherwise\r
+                       = CtxNonfix\r
+       | otherwise     \r
+               = CtxRecord \r
+where\r
+       is_tuple name \r
+               #! size_name = size name\r
+               = (size_name == 7 || size_name == 8)\r
+               && name.[0] == '_'\r
+               && name.[1] == 'T'\r
+               && name.[2] == 'u'\r
+               && name.[3] == 'p'\r
+               && name.[4] == 'l'\r
+               && name.[5] == 'e'\r
+               && isDigit name.[6]\r
+               && (size_name == 7 || isDigit name.[7])\r
+       \r
+mkContext {gcd_prio=GenConsPrio assoc prio, gcd_name} \r
+       = CtxInfix gcd_name assoc prio GenConsAssocNone\r
+\r
+needParenthesis :: Context Context -> Bool\r
+needParenthesis CtxNone outer_ctx              = abort "needParenthesis: this_ctx = CtxNone"\r
+needParenthesis this_ctx CtxNullary            = abort "needParenthesis: outer_ctx = CtxNullary"\r
+needParenthesis CtxNullary outer_ctx   = False\r
+needParenthesis CtxTuple outer_ctx             = True          // the tuple parenthesis\r
+needParenthesis CtxRecord outer_ctx    = False\r
+needParenthesis CtxNonfix CtxNone              = False\r
+needParenthesis CtxNonfix CtxTuple             = False\r
+needParenthesis CtxNonfix CtxRecord            = False\r
+needParenthesis CtxNonfix CtxNonfix            = True\r
+needParenthesis CtxNonfix (CtxInfix _ _ _ _) = False\r
+needParenthesis (CtxInfix _ _ _ _) CtxNone = False\r
+needParenthesis (CtxInfix _ _ _ _) CtxNullary = True\r
+needParenthesis (CtxInfix _ _ _ _) CtxTuple = False\r
+needParenthesis (CtxInfix _ _ _ _) CtxRecord = False\r
+needParenthesis (CtxInfix _ _ _ _) CtxNonfix = True // False // PK\r
+needParenthesis (CtxInfix _ this_assoc this_prio _) (CtxInfix _ outer_assoc outer_prio branch) \r
+       =       outer_prio > this_prio \r
+       ||  (outer_prio == this_prio && not (this_assoc == outer_assoc && this_assoc == branch))\r
+\r
+//derive bimap PrintState\r
+\r
+//-------------------------------------------------------------------------------------\r
+\r
+\r
+printChar :: Char (PrintState *s) -> (PrintState *s) | PrintOutput s \r
+printChar ch s=:{ps_output}\r
+       # ps_output = printOutput ch ps_output\r
+       = {s & ps_output = ps_output}\r
+\r
+printCharLiteral '\\'  = printChar '\\' $ printChar '\\'\r
+printCharLiteral '\n'  = printChar '\\' $ printChar '\n'\r
+printCharLiteral '\t'  = printChar '\\' $ printChar '\t'\r
+printCharLiteral '\b'  = printChar '\\' $ printChar '\b'\r
+printCharLiteral '\''  = printChar '\\' $ printChar '\''\r
+printCharLiteral '\"'  = printChar '\\' $ printChar '\"'\r
+printCharLiteral '\0'  = printChar '\\' $ printChar '\0'\r
+printCharLiteral c             = printChar c\r
+\r
+printString str\r
+       #! size_str = size str\r
+       = do_it 0 size_str str\r
+where\r
+       do_it i n str\r
+               | i == n\r
+                       = id\r
+                       = printChar str.[i]\r
+                       $ do_it (inc i) n str \r
+\r
+printStringLiteral str\r
+       #! size_str = size str\r
+       = do_it 0 size_str str\r
+where\r
+       do_it i n str\r
+               | i == n\r
+                       = id\r
+                       = printCharLiteral str.[i]\r
+                       $ do_it (inc i) n str \r
+\r
+\r
+printList f xs ps=:{ps_context}\r
+       =       { print_list f xs { ps & ps_context = CtxNone} \r
+               & ps_context = ps_context \r
+               }\r
+where\r
+       print_list f [] = id\r
+       print_list f [x] = f x\r
+       print_list f [x:xs] \r
+               = f x                   \r
+               $ printString ", "\r
+               $ print_list f xs       \r
+\r
+//-------------------------------------------------------------------------------------\r
+generic gPrint a :: a (PrintState *s) -> (PrintState *s) | PrintOutput s\r
+gPrint{|Int|} x st \r
+       = printString (toString x) st\r
+gPrint{|Real|} x st \r
+       # str = toString x\r
+       | all isDigit [c\\c<-:str] // add .0 if needed\r
+               = printString (str +++ ".0") st \r
+       | str.[0] == '.'\r
+               = printString ("0" +++ str) st\r
+       | otherwise     \r
+               = printString str st\r
+gPrint{|Bool|} x st \r
+       = printString (toString x) st\r
+gPrint{|Char|} x st \r
+       = printChar '\'' $ printCharLiteral x $ printChar '\'' @ st \r
+gPrint{|String|} x st \r
+       = printChar '"'\r
+       $ printStringLiteral x \r
+       $ printChar '"'\r
+       @ st\r
+gPrint{|UNIT|} x st \r
+       = st\r
+       \r
+gPrint{|EITHER|} fl fr (LEFT x) st = fl x st\r
+gPrint{|EITHER|} fl fr (RIGHT x) st = fr x st\r
+\r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxNone}\r
+       = abort "gOutput{|PAIR|}: CtxNone\n" \r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxNullary}\r
+       = abort "gOutput{|PAIR|}: CtxNullary\n" \r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxTuple}\r
+       = fx x $ printString ", " $ fy y @ st\r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxRecord}\r
+       = fx x $ printString ", " $ fy y @ st\r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxNonfix}\r
+       = fx x $ printChar ' ' $ fy y @ st      \r
+gPrint{|PAIR|} fx fy (PAIR x y) st=:{ps_context = CtxInfix name assoc prio branch} \r
+       # st = fx x {st & ps_context = CtxInfix name assoc prio GenConsAssocLeft} \r
+       # st = printChar ' ' $ printStringLiteral name $ printChar ' ' @ st\r
+       # st = fy y {st & ps_context = CtxInfix name assoc prio GenConsAssocRight} \r
+       = {st & ps_context = CtxInfix name assoc prio branch} \r
+\r
+gPrint{|CONS of d|} print_arg (CONS x) st=:{ps_context}\r
+       #! ctx = mkContext d\r
+       #! st = { st & ps_context = ctx }\r
+       | needParenthesis ctx ps_context\r
+               =       { printChar '(' \r
+                       $ print print_arg ctx \r
+                       $ printChar ')' \r
+                       @ st \r
+                       & ps_context = ps_context \r
+                       }\r
+       | otherwise\r
+               = { print print_arg ctx st & ps_context = ps_context }\r
+where\r
+       print print_arg CtxNone                         \r
+               = abort "gOutput{|CONS|}: CtxNone\n"\r
+       print print_arg CtxNullary              \r
+               = printStringLiteral d.gcd_name \r
+       print print_arg CtxTuple\r
+               = print_arg x\r
+       print print_arg CtxRecord               \r
+               = printString "{ " \r
+               $ foldSt printChar (tl [c\\c<-:d.gcd_name]) //printStringLiteral d.gcd_name \r
+               $ printString " | "\r
+               $ print_arg x\r
+               $ printString " }"\r
+       print print_arg CtxNonfix               \r
+               = printStringLiteral d.gcd_name\r
+               $ printChar ' '\r
+               $ print_arg x \r
+       print print_arg (CtxInfix _ _ _ _)              \r
+               = print_arg x\r
+\r
+gPrint{|FIELD of d|} f (FIELD x) st\r
+       = printStringLiteral d.gfd_name\r
+       $ printString " = " \r
+       $ f x \r
+       @ st\r
+gPrint{|OBJECT|} f (OBJECT x) st\r
+       = f x st        \r
+       \r
+gPrint{|[]|} f xs st\r
+       = printChar '['\r
+       $ printList f xs \r
+       $ printChar ']'\r
+       @ st\r
+\r
+gPrint{|{}|} f xs st\r
+       = printChar '{'\r
+       $ printList f [ x \\ x <-: xs] \r
+       $ printChar '}'\r
+       @ st\r
+\r
+gPrint{|{!}|} f xs st\r
+       = printChar '{'\r
+       $ printList f [ x \\ x <-: xs] \r
+       $ printChar '}'\r
+       @ st\r
+\r
+//derive gOutput (,), (,,), (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,)\r
+       \r
+//-------------------------------------------------------------------------------------\r
+(<<-) infixl 0 :: (PrintState *s) a -> *(PrintState *s) | gPrint{|*|} a & PrintOutput s\r
+(<<-) s x = gPrint{|*|} x s\r
+\r
+mkPrintState :: *s -> PrintState *s | PrintOutput s\r
+mkPrintState s =\r
+       { ps_output = s\r
+       , ps_context = CtxNone\r
+       } \r
+\r
+mkStringPrintState :: PrintState StringOutput\r
+mkStringPrintState = mkPrintState {so_pos = 0, so_str = createArray 16 '\0'}\r
+\r
+openFilePrintState :: String *fs -> (Maybe (PrintState *File), *fs) | FileSystem fs\r
+openFilePrintState name fs \r
+       # (ok, file, fs) = fopen name FWriteText fs\r
+       | ok    = (Just (mkPrintState file), fs)\r
+                       = (Nothing, fs)\r
+\r
+printToString :: a -> String | gPrint{|*|} a\r
+printToString x\r
+       # string_output = (mkStringPrintState <<- x).ps_output\r
+       = string_output.so_str % (0,string_output.so_pos-1)\r
+\r
+//-------------------------------------------------------------------------------------\r
+\r
+//Start = 1
\ No newline at end of file