aboutsummaryrefslogtreecommitdiff
path: root/Sil/Util.icl
blob: 35b8522bc4a5cb20a6a3da6e8ac3fd6803e36518 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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}

incIndent :: PrintState -> PrintState
incIndent ps = {ps & indent=inc ps.indent}

decIndent :: PrintState -> PrintState
decIndent ps = {ps & indent=dec ps.indent}

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 (If c t Nothing) = st <+ "if (" <+ c <+ ") {\r\n" <+
		print (incIndent st) t <+ "\r\n" <+ st <+ "}"
	print st (If c t (Just e)) = st <+ "if (" <+ c <+ ") {\r\n" <+
		print st` t <+ "\r\n" <+ st <+ "} else {\r\n" <+
		print st` e <+ "\r\n" <+ st <+ "}"
	where st` = incIndent st
	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 (If c t e)        = "if (" <+ c <+ ") ..."
	toString (MachineStm s)    = "|~" <+ s
	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 <+ ")"
	toString (BuiltinApp op e)      = op <+ "(" <+ e <+ ")"
	toString (BuiltinApp2 e1 op e2) = "(" <+ e1 <+ ") " <+ op <+ " (" <+ e2 <+ ")"

instance toString Op1
where
	toString Neg = "~"

instance toString Op2
where
	toString Add    = "+"
	toString Sub    = "-"
	toString Mul    = "*"
	toString Div    = "/"
	toString Rem    = "%"
	toString Equals = "=="
	toString LogOr  = "||"
	toString LogAnd = "&&"

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