aboutsummaryrefslogtreecommitdiff
path: root/Sil/Util.icl
blob: ad7cfacf4c700e604a56654de8b787d3188403ed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
implementation module Sil.Util

import _SystemArray
import StdEnum
from StdFunc import id
import StdInt
import StdList
import StdOverloaded
import StdString

from Data.Func import $
import Data.List
import Data.Maybe
import Text

import Sil.Parse
import Sil.Syntax

:: PrintState =
	{ indent :: Int
	}

instance zero PrintState where zero = {indent=0}

instance toString PrintState where toString st = {'\t' \\ _ <- [1..st.indent]}

instance PrettyPrinter [Token]
where
	print st []             = ""
	print st [t]            = toString t
	print st [t:ts=:[t`:_]] = toString t +++ spaceBetween t t` +++ print st` ts
	where
		st` = {st & indent=indent`}
		indent` = newIndent t t` st.indent

		spaceBetween :: Token Token -> String
		spaceBetween _           TBraceClose = newline
		spaceBetween TParenOpen  _           = ""
		spaceBetween TParenClose TBraceOpen  = space
		spaceBetween TParenClose _           = ""
		spaceBetween TBraceOpen  _           = newline
		spaceBetween TBraceClose _           = newline
		spaceBetween TComma      _           = space
		spaceBetween TSemicolon  _           = newline
		spaceBetween TAssign     _           = space
		spaceBetween (TLit _)    _           = space
		spaceBetween TIf         _           = space
		spaceBetween TWhile      _           = space
		spaceBetween TReturn     _           = space
		spaceBetween (TName _)   TParenClose = ""
		spaceBetween (TName _)   TSemicolon  = ""
		spaceBetween (TName _)   _           = space

		newline = "\r\n" +++ {'\t' \\ _ <- [1..indent`]}
		space = " "

		newIndent :: Token Token -> Int -> Int
		newIndent TBraceOpen  _           = inc
		newIndent _           TBraceClose = dec
		newIndent _           _           = id

instance PrettyPrinter Program
where
	print st prog = p st prog.p_funs
	where
		p :: PrintState [Function] -> String
		p _  []     = ""
		p st [f]    = print st f
		p st [f:fs] = print st f <+ "\r\n\r\n" <+ p st fs

instance PrettyPrinter Function
where
	print st f = st <+ f.f_type <+ " " <+ f.f_name
		<+ "(" <+ printersperse ", " f.f_args <+ ") {\r\n"
		<+ print {st & indent=st.indent+1} f.f_code <+ "\r\n" <+ st <+ "}"

instance PrettyPrinter CodeBlock
where
	print st cb = concat $ intersperse "\r\n" $
		[print st x \\ x <- cb.cb_init] ++ [print st x \\ x <- cb.cb_content]

instance PrettyPrinter Initialisation
where
	print st init = st <+ init.init_type <+ " " <+ init.init_name <+ ";"

instance PrettyPrinter Statement where print st stm = st <+ stm <+ ";"

instance toString Statement
where
	toString (Declaration n a) = n <+ " " <+ TAssign <+ " " <+ a
	toString (Application app) = toString app
	toString (Return Nothing)  = "return"
	toString (Return (Just a)) = "return " <+ a <+ ""
	toString _                 = "<<unimplemented Statement>>"

instance toString Type
where
	toString TBool = "Bool"
	toString TInt  = "Int"
	toString TVoid = "Void"

instance toString Arg where toString arg = arg.arg_type <+ " " <+ arg.arg_name

instance toString Application
where
	toString (Name n)      = n
	toString (Literal lit) = toString lit
	toString (App n args)  = n <+ "(" <+ printersperse ", " args <+ ")"

instance toString Literal
where
	toString (BLit b) = toString b
	toString (ILit i) = toString i

printersperse :: a [b] -> String | toString a & toString b
printersperse _ []     = ""
printersperse _ [x]    = toString x
printersperse g [x:xs] = x <+ g <+ printersperse g xs