0 | module Go.AST.Printer
2 | import Control.Monad.Either
6 | import Data.List.Quantifiers
16 | = PrintFileError FileError
19 | implementation Show PrintError where
21 | PrintFileError e => show e
24 | PrinterMonad : (Type -> Type) -> Type -> Type
25 | PrinterMonad io a = EitherT PrintError io a
28 | data Indent = MkIndent Nat
32 | zeroIndent = MkIndent 0
35 | increaseIndent : Indent -> Indent
36 | increaseIndent (MkIndent i) = MkIndent (i+1)
39 | interface Printer a where
40 | constructor MkPrinter
41 | print : HasIO io => File -> {auto indent : Indent} -> a -> PrinterMonad io ()
43 | pPutStr : HasIO io => {auto file : File} -> String -> PrinterMonad io ()
44 | pPutStr {file} str = MkEitherT $
fPutStr file str >>= \case
45 | Left e => pure $
Left $
PrintFileError e
46 | Right a => pure $
Right a
48 | printNewLine : HasIO io => {auto file : File} -> PrinterMonad io ()
49 | printNewLine = pPutStr "\n"
51 | printIndent : HasIO io => {auto file : File} -> {auto indent : Indent} -> PrinterMonad io ()
52 | printIndent {indent = (MkIndent i)} =
53 | let str = concat $
replicate i "\t"
56 | printComments : HasIO io => {auto file : File} -> {auto indent : Indent} -> List Comment -> PrinterMonad io ()
57 | printComments [] = pure ()
58 | printComments [x] = do
61 | printComments (x::xs) = do
71 | implementation Printer BadExpression where
72 | print file be = pPutStr "/* Evaluated BadExpression */"
75 | implementation Printer Identifier where
76 | print file i = pPutStr i.name
79 | implementation Printer BasicLiteral where
81 | let value = case bl.kind of
82 | MkString => "\"\{bl.value}\""
83 | MkChar => "'\{bl.value}'"
88 | implementation Expression (CompositLiteral t es) => Printer t => All Printer es => Printer (CompositLiteral t es) where
92 | Just t => print file t
93 | case cl.expressions of
94 | x1::x2::x3::xs => do
96 | multiLine cl.expressions
102 | singleLine cl.expressions
105 | singleLine : {0 ts : List Type} -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
106 | singleLine [] = pure ()
107 | singleLine {ps = [p]} [x] = print file x
108 | singleLine {ps = (p::ps)} (x::xs) = do
114 | inci = increaseIndent indent
116 | multiLine : {0 ts : List Type} -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
117 | multiLine [] = pure ()
118 | multiLine {ps = [p]} [x] = do
120 | printIndent {indent = inci}
121 | print {indent = inci} file x
123 | multiLine {ps = (p::ps)} (x::xs) = do
125 | printIndent {indent = inci}
126 | print {indent = inci} file x
131 | implementation Expression (FunctionLiteral ts ps rs sts) => Printer (FunctionType ts ps rs) => Printer (BlockStatement sts) => Printer (FunctionLiteral ts ps rs sts) where
138 | implementation Expression (CallExpression f as e) => Printer f => All Printer as => Printer (CallExpression f as e) where
140 | print file ce.function
145 | many : { 0 ts : List Type } -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
147 | many {ps = [p]} [x] = print file x
148 | many {ps = [p1,p2]} [x,y] = do
152 | many {ps = (p::ps)} (x::xs) = do
158 | implementation Expression (ParenExpression e) => Printer e => Printer (ParenExpression e) where
161 | print file pe.expression
165 | implementation Expression (CastExpression t e) => Printer t => Printer e => Printer (CastExpression t e) where
169 | print file ce.expression
173 | implementation Expression (TypeAssertExpression e t) => Printer e => Printer t => Printer (TypeAssertExpression e t) where
174 | print file tae = do
175 | print file tae.expression
177 | print file tae.type
181 | implementation Expression (MakeExpression t es) => Printer t => All Printer es => Printer (MakeExpression t es) where
185 | many me.expressions
188 | many : { 0 ts : List Type } -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
190 | many {ps = [p]} [x] = do
193 | many {ps = (p::ps)} (x::xs) = do
199 | implementation Expression (SelectorExpression e) => Printer e => Printer (SelectorExpression e) where
201 | print file se.expression
203 | print file se.selector
206 | implementation Expression (IndexExpression e i) => Printer e => Printer i => Printer (IndexExpression e i) where
208 | print file ie.expression
210 | print file ie.index
214 | implementation Expression (SliceExpression e l h m) => Printer e => Printer l => Printer h => Printer m => Printer (SliceExpression e l h m) where
216 | print file se.expression
219 | Nothing => pPutStr ":"
225 | Just h => print file h
234 | implementation Expression (UnaryExpression e) => Printer e => Printer (UnaryExpression e) where
236 | pPutStr $
show ue.operator
237 | print file ue.expression
240 | implementation Expression (StarExpression e) => Printer e => Printer (StarExpression e) where
243 | print file se.expression
246 | implementation Expression (BinaryExpression e1 e2) => Printer e1 => Printer e2 => Printer (BinaryExpression e1 e2) where
248 | print file bo.first
250 | pPutStr $
show bo.operator
255 | implementation Expression (KeyValueExpression e1 e2) => Printer e1 => Printer e2 => Printer (KeyValueExpression e1 e2) where
256 | print file kve = do
259 | print file kve.value
264 | implementation Printer ImportSpec where
265 | print file is = case is.name of
266 | Nothing => print file is.path
273 | implementation Specification (TypeSpec ts t) => Printer (FieldList ts) => Printer t => Printer (TypeSpec ts t) where
276 | case ts.typeParams of
286 | implementation Specification (ValueSpec t es) => Printer t => All Printer es => Printer (ValueSpec t es) where
290 | Just (MkCommentGroup cs) => do
291 | printComments $
forget cs
294 | printNames $
List1.forget vs.names
300 | when (not $
null vs.values) $
do
302 | printValues vs.values
307 | printComments $
forget cg.comments
309 | printNames : List Identifier -> PrinterMonad io ()
310 | printNames [] = pure ()
311 | printNames [x] = print file x
312 | printNames (x::xs) = do
317 | printValues : { 0 ts : List Type } -> {auto ps : All Printer ts } -> HList ts -> PrinterMonad io ()
318 | printValues [] = pure ()
319 | printValues {ps = [p]} [x] = print file x
320 | printValues {ps = (p::ps)} (x::xs) = do
328 | implementation Printer BadStatement where
329 | print file be = pPutStr "/* Evaluated BadStatement */"
332 | implementation Statement (ExpressionStatement e) => Printer e => Printer (ExpressionStatement e) where
337 | printComments $
forget cg.comments
340 | print file es.expression
345 | printComments $
forget cg.comments
348 | implementation Statement (DeclarationStatement d) => Printer d => Printer (DeclarationStatement d) where
349 | print file d = print file d.declaration
352 | implementation Statement (BlockStatement sts) => All Printer sts => Printer (BlockStatement sts) where
353 | print file bs @{stss} @{ps} = do
355 | many bs.statements {ps}
360 | inci = increaseIndent indent
362 | many : { 0 sts : List Type } -> { ps : All Printer sts } -> HList sts -> PrinterMonad io ()
364 | many {ps = [p]} [x] = do
365 | printIndent {indent = inci}
366 | print {indent = inci} file x
368 | many {ps = (p::ps)} (x::xs) = do
369 | printIndent {indent = inci}
370 | print {indent = inci} file x
375 | implementation Statement (AssignmentStatement ls rs) => All Printer ls => All Printer rs => Printer (AssignmentStatement ls rs) where
379 | Just (MkCommentGroup cs) => do
380 | printComments $
forget cs
385 | pPutStr $
show as.token
390 | Just (MkCommentGroup cs) => do
392 | printComments $
forget cs
393 | when (1 < length cs) printNewLine
395 | many : {0 es : List Type} -> {auto ps : All Printer es} -> HList es -> PrinterMonad io ()
397 | many {ps = [p]} [x] = do
399 | many {ps = (p::ps)} (x::xs) = do
405 | implementation Statement (IncDecStatement e o) => Show (IncOrDec o) => Printer e => Printer (IncDecStatement e o) where
406 | print file ids = do
407 | print file ids.expression
408 | pPutStr $
show ids.token
411 | implementation Statement (DeferStatement f as e) => Printer (CallExpression f as e) => Printer (DeferStatement f as e) where
417 | implementation Statement (LabeledStatement s) => Printer s => Printer (LabeledStatement s) where
419 | pPutStr $
ls.label.name ++ ": "
422 | print file ls.statement
425 | implementation Statement (BranchStatement kw) => Printer (BranchStatement kw) where
427 | let kw = case bs.token of
429 | IsContinue => "continue"
431 | IsFallthrough => "fallthrough"
432 | label = case bs.label of
433 | Just l => " " ++ l.name
435 | pPutStr $
kw ++ label
438 | implementation Statement (ForStatement i c p sts) => Printer i => Printer c => Printer p => Printer (BlockStatement sts) => Printer (ForStatement i c p sts) where
441 | case (fs.init, fs.condition, fs.post) of
442 | (Nothing, Nothing, Nothing) => pure ()
443 | (Nothing, Just c, Nothing) => do
448 | maybe (pure ()) (print file) fs.init
450 | maybe (pure ()) (print file) fs.condition
452 | maybe (pure ()) (print file) fs.post
458 | implementation Statement (KeyValueRangeStatement k v a r sts) => Printer k => Printer v => Show (AssignOrDefine a) => Printer r => Printer (BlockStatement sts) => Printer (KeyValueRangeStatement k v a r sts) where
463 | print file rs.value
464 | pPutStr " \{show rs.token} range "
465 | print file rs.expression
470 | implementation Statement (ValueRangeStatement v a r sts) => Printer v => Show (AssignOrDefine a) => Printer r => Printer (BlockStatement sts) => Printer (ValueRangeStatement v a r sts) where
473 | print file rs.value
474 | pPutStr " \{show rs.token} range "
475 | print file rs.expression
480 | implementation Statement (RangeStatement r sts) => Printer r => Printer (BlockStatement sts) => Printer (RangeStatement r sts) where
482 | pPutStr "for range "
483 | print file rs.expression
488 | implementation Statement (IfStatement i c sts e) => Printer i => Printer c => Printer (BlockStatement sts) => Printer e => Printer (IfStatement i c sts e) where
496 | print file is.condition
499 | case is.elseBranch of
506 | implementation Statement (SwitchStatement i e sts) => Printer i => Printer e => All Printer sts => Printer (SwitchStatement i e sts) where
520 | printBody ss.body.statements
525 | printBody : { 0 sts : List Type } -> {auto ps : All Printer sts } -> HList sts -> PrinterMonad io ()
526 | printBody [] = pure ()
527 | printBody {ps = [p]} [x] = do
531 | printBody {ps = (p::ps)} (x::xs) = do
538 | implementation Statement (CaseClause es sts) => All Printer es => All Printer sts => Printer (CaseClause es sts) where
541 | [] => pPutStr "default"
542 | _ => pPutStr "case "
547 | printList : {0 ts : List Type} -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
548 | printList [] = pure ()
549 | printList {ps = [p]} [x] = print file x
550 | printList {ps = p::ps} (x::xs) = do
556 | inci = increaseIndent indent
558 | printBody : {0 ts : List Type} -> {auto ps : All Printer ts} -> HList ts -> PrinterMonad io ()
559 | printBody [] = pure ()
560 | printBody {ps = [p]} [x] = do
562 | printIndent {indent = inci}
563 | print {indent = inci} file x
564 | printBody {ps = p::ps} (x::xs) = do
566 | printIndent {indent = inci}
567 | print {indent = inci} file x
571 | implementation Statement (ReturnStatement rs) => All Printer rs => Printer (ReturnStatement rs) where
576 | printComments $
forget ds.comments
582 | many : {0 es : List Type} -> {auto ps : All Printer es} -> HList es -> PrinterMonad io ()
584 | many {ps = [p]} [x] = do
587 | many {ps = (p::ps)} (x::xs) = do
596 | implementation GoType t => Printer t => Printer (Field t) where
602 | when (not $
null f.names) $
pPutStr " "
605 | printNames : List Identifier -> PrinterMonad io ()
606 | printNames [] = pure ()
607 | printNames [x] = print file x
608 | printNames (x::xs) = do
614 | implementation All Printer ts => Printer (FieldList ts) where
615 | print file fl = many fl
617 | many : { 0 ts : List Type } -> {auto ps : All Printer ts } -> FieldList ts -> PrinterMonad io ()
619 | many {ps = (p::ps)} [x] = print file x
620 | many {ps = (p::ps)} (x::xs) = do
628 | implementation Printer BadType where
629 | print file bt = pPutStr "/* Evaluating Bad Type */"
632 | implementation Printer TypeIdentifier where
642 | implementation GoType (StructType es) => All Printer es => Printer (FieldList es) => Printer (StructType es) where
644 | pPutStr "struct {\n"
650 | inci = increaseIndent indent
652 | many : { 0 ts : List Type } -> {auto ps : All Printer ts} -> FieldList ts -> PrinterMonad io ()
654 | many {ps = (p::ps)} (x::xs) = do
655 | printIndent {indent = inci}
656 | print {indent = inci} file x
661 | implementation GoType (ArrayType l e) => Printer l => Printer e => Printer (ArrayType l e) where
664 | maybe (pure ()) (print file) at.length
666 | print file at.element
669 | implementation GoType (MapType k v) => Printer k => Printer v => Printer (MapType k v) where
674 | print file mt.value
676 | printReturnTypes : HasIO io => All Printer rs => File -> FieldList rs -> PrinterMonad io ()
677 | printReturnTypes file fl = case fl of
678 | [] => print file fl
680 | let parens = 2 <= length x.names
682 | when parens $
pPutStr "("
684 | when parens $
pPutStr ")"
691 | implementation GoType (FunctionType ts ps rs) => All Printer ts => All Printer ps => All Printer rs => Printer (FunctionType ts ps rs) where
694 | print file ft.params
696 | printReturnTypes file ft.results
701 | implementation Declaration (FuncDeclaration rcs ts ps rs sts) => All Printer ps => All Printer rs => Printer (BlockStatement sts) => Printer (FuncDeclaration rcs ts ps rs sts) where
706 | printComments $
forget ds.comments
710 | pPutStr fd.name.name
712 | print file fd.type.params
714 | printReturnTypes file fd.type.results
719 | implementation Declaration (GenericDeclaration k es) => All Printer es => Show (GenericDeclarationToken k) => Printer (GenericDeclaration k es) where
721 | let multiple = hasMany gd.specs
722 | inci = if multiple then increaseIndent indent else indent
723 | pPutStr $
show gd.token
727 | printIndent {indent=inci}
729 | when multiple $
pPutStr "\n)"
731 | hasMany : {0 ts : List Type} -> HList ts -> Bool
733 | hasMany [_] = False
736 | many : {0 ts : List Type} -> {auto ps : All Printer ts} -> Indent -> HList ts -> PrinterMonad io ()
737 | many _ [] = pure ()
738 | many {ps = [p]} i [x] = print {indent=i} file x
739 | many {ps = (p::ps)} i (x::xs) = do
740 | print {indent=i} file x
742 | printIndent {indent=i}
748 | implementation All Declaration ds => All Printer ds => Printer (Go.File ds) where
751 | printPackage f.packageName
755 | printImports f.imports
763 | printDecls : { 0 ds : List Type } -> { auto ps : All Printer ds } -> HList ds -> PrinterMonad io ()
764 | printDecls {ds = []} Nil = pure ()
765 | printDecls {ds = [x]} {ps = [p]} [d] = print file d
766 | printDecls {ds = x::xs} {ps = p::ps} (d::ds) = do
773 | printPackage : Identifier -> PrinterMonad io ()
774 | printPackage i = pPutStr "package \{i.name}"
776 | printImports : List ImportSpec -> PrinterMonad io ()
777 | printImports = \case
783 | pPutStr "import (\n"
784 | ignore $
for xs $
\spec => do
785 | printIndent {indent = increaseIndent indent}
791 | printFile : HasIO io => All Declaration ds => Printer (Go.File ds) => (folder : String) -> Go.File ds -> io (Either PrintError ())
792 | printFile folder f = do
793 | withFile "\{folder}/\{f.name}" WriteTruncate (pure . PrintFileError) $
\h =>
794 | runEitherT $
print h f