summaryrefslogtreecommitdiff
path: root/lib/Language/Elna/AST.hs
blob: ac86e6360973bfa431847758e8c3081cb7461c24 (plain)
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
module Language.Elna.AST
    ( VariableAccess(..)
    , Condition(..)
    , Declaration(..)
    , Expression(..)
    , Identifier(..)
    , Literal(..)
    , Parameter(..)
    , Program(..)
    , Statement(..)
    , VariableDeclaration(..)
    , TypeExpression(..)
    ) where

import Data.Int (Int32)
import Data.List (intercalate)
import Data.Word (Word16, Word32)
import Data.Char (chr)
import Language.Elna.Location (Identifier(..), showArrayType)
import Numeric (showHex)

data TypeExpression
    = NamedType Identifier
    | ArrayType Word32 TypeExpression
    deriving Eq

instance Show TypeExpression
  where
    show (NamedType typeName) = show typeName
    show (ArrayType elementCount typeName) = showArrayType elementCount typeName

data Literal
    = IntegerLiteral Int32
    | HexadecimalLiteral Int32
    | CharacterLiteral Word16
    | BooleanLiteral Bool
    deriving Eq

instance Show Literal
  where
    show (IntegerLiteral integer) = show integer
    show (HexadecimalLiteral integer) = '0' : 'x' : showHex integer ""
    show (CharacterLiteral character) =
        '\'' : chr (fromEnum character) : ['\'']
    show (BooleanLiteral boolean)
        | boolean = "true"
        | otherwise = "false"

data VariableAccess
    = VariableAccess Identifier
    | ArrayAccess VariableAccess Expression
    deriving Eq

instance Show VariableAccess
  where
    show (VariableAccess variableName) = show variableName
    show (ArrayAccess arrayAccess elementIndex) =
        concat [show arrayAccess, "[", show elementIndex, "]"]

data Expression
    = VariableExpression VariableAccess
    | LiteralExpression Literal
    | NegationExpression Expression
    | SumExpression Expression Expression
    | SubtractionExpression Expression Expression
    | ProductExpression Expression Expression
    | DivisionExpression Expression Expression
    deriving Eq

instance Show Expression
  where
    show (VariableExpression variable) = show variable
    show (LiteralExpression literal) = show literal
    show (NegationExpression negation) = '-' : show negation
    show (SumExpression lhs rhs) = concat [show lhs, " + ", show rhs]
    show (SubtractionExpression lhs rhs) = concat [show lhs, " - ", show rhs]
    show (ProductExpression lhs rhs) = concat [show lhs, " * ", show rhs]
    show (DivisionExpression lhs rhs) = concat [show lhs, " / ", show rhs]

data Condition
    = EqualCondition Expression Expression
    | NonEqualCondition Expression Expression
    | LessCondition Expression Expression
    | GreaterCondition Expression Expression
    | LessOrEqualCondition Expression Expression
    | GreaterOrEqualCondition Expression Expression
    deriving Eq

instance Show Condition
  where
    show (EqualCondition lhs rhs) = concat [show lhs, " = ", show rhs]
    show (NonEqualCondition lhs rhs) = concat [show lhs, " # ", show rhs]
    show (LessCondition lhs rhs) = concat [show lhs, " < ", show rhs]
    show (GreaterCondition lhs rhs) = concat [show lhs, " > ", show rhs]
    show (LessOrEqualCondition lhs rhs) = concat [show lhs, " <= ", show rhs]
    show (GreaterOrEqualCondition lhs rhs) = concat [show lhs, " >= ", show rhs]

data Statement
    = EmptyStatement
    | AssignmentStatement VariableAccess Expression
    | IfStatement Condition Statement (Maybe Statement)
    | WhileStatement Condition Statement
    | CompoundStatement [Statement]
    | CallStatement Identifier [Expression]
    deriving Eq

instance Show Statement
  where
    show EmptyStatement = ";"
    show (AssignmentStatement lhs rhs) =
        concat [show lhs, " := ", show rhs, ";"]
    show (IfStatement condition if' else') = concat
        [ "if (", show condition, ") "
        , show if'
        , maybe "" ((<> " else ") . show) else'
        ]
    show (WhileStatement expression statement) =
        concat ["while (", show expression, ") ", show statement, ";"]
    show (CompoundStatement statements) =
        concat ["{\n", unlines (show <$> statements), " }"]
    show (CallStatement name parameters) = show name <> "("
        <> intercalate ", " (show <$> parameters) <> ")"

data Parameter = Parameter Identifier TypeExpression Bool
    deriving Eq

instance Show Parameter
  where
    show (Parameter identifier typeName ref) = concat
        [ if ref then "ref " else ""
        , show identifier, ": ", show typeName
        ]

data VariableDeclaration =
    VariableDeclaration Identifier TypeExpression
    deriving Eq

instance Show VariableDeclaration
  where
    show (VariableDeclaration identifier typeExpression) =
        concat ["var ", show identifier, ": " <> show typeExpression, ";"]

data Declaration
    = TypeDefinition Identifier TypeExpression
    | ProcedureDefinition Identifier [Parameter] [VariableDeclaration] [Statement]
    deriving Eq

instance Show Declaration
  where
    show (TypeDefinition identifier typeExpression) =
        concat ["type ", show identifier, " = ", show typeExpression, ";"]
    show (ProcedureDefinition procedureName parameters variables body)
        = "proc " <> show procedureName <> showParameters parameters <> " {\n"
        <> unlines (("  " <>) . show <$> variables)
        <> unlines (("  " <>) . show <$> body)
        <> "}"

newtype Program = Program [Declaration]
    deriving Eq

instance Show Program
  where
    show (Program declarations) = unlines (show <$> declarations)

showParameters :: [Parameter] -> String
showParameters parameters =
    "(" <> intercalate ", " (show <$> parameters) <> ")"