summaryrefslogtreecommitdiff
path: root/ast.hs
blob: 9a4373d2c4cca91670856f3a4c571d5c1062bdeb (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
module AST where

import Data.List
import Data.Word


type Byte = Word8
type Offset = Int


newtype Program = Program [Instruction]
  deriving (Show, Eq)

data Instruction
    = IAdd Byte Offset
    | ISet Byte Offset
    | IMove Offset [(Offset, Byte)]  -- IMove from [(to, multiplier)]
    | ISlide Offset
    | ILoop [Instruction] Offset
    | IInput Offset
    | IOutput Offset
    | IStart
  deriving (Show, Eq)

isIAdd :: Instruction -> Bool
isIAdd (IAdd _ _) = True
isIAdd _ = False

isISet :: Instruction -> Bool
isISet (ISet _ _) = True
isISet _ = False

isIMove :: Instruction -> Bool
isIMove (IMove _ _) = True
isIMove _ = False

isISlide :: Instruction -> Bool
isISlide (ISlide _) = True
isISlide _ = False

offsetOf :: Instruction -> Offset
offsetOf (IAdd _ o) = o
offsetOf (ISet _ o) = o
offsetOf (IMove o _) = o
offsetOf (ISlide _) = undefined
offsetOf (ILoop _ _) = undefined
offsetOf (IInput o) = o
offsetOf (IOutput o) = o
offsetOf IStart = 0

astSuccinct :: Program -> String
astSuccinct (Program inss) = concatMap insSuccinct inss
  where
    insSuccinct :: Instruction -> String
    insSuccinct (IAdd v o) =
        let sv = signedByte v
        in (if sv >= 0 then "+" else "") ++ show (signedByte v) ++ ',' : show o
    insSuccinct (ISet v o) = '=' : show (signedByte v) ++ ',' : show o
    insSuccinct (IMove from tos) =
        'M' : show from ++ '(' : intercalate "," (map (\(o,m) -> show o ++ '*' : show m) tos) ++ ")"
    insSuccinct (ISlide o) = '>' : show o
    insSuccinct (ILoop inss' off) = "[(" ++ show off ++ ')' : concatMap insSuccinct inss' ++ "]"
    insSuccinct (IInput o) = ',' : show o
    insSuccinct (IOutput o) = '.' : show o
    insSuccinct IStart = "$"

    signedByte :: Byte -> Int
    signedByte v
        | v < 128 = fromIntegral v
        | otherwise = fromIntegral v - 256