Skip to content

Commit 09b6c68

Browse files
committed
release(v1.1): errors & backend
2 parents e48e668 + 66d72ab commit 09b6c68

File tree

11 files changed

+229
-120
lines changed

11 files changed

+229
-120
lines changed

Kroha.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cabal-version: 1.12
55
-- see: https://github.com/sol/hpack
66

77
name: Kroha
8-
version: 1.0.0.0
8+
version: 1.1.0.0
99
description: Please see the README on GitHub at <https://github.com/vorotynsky/HLasm#readme>
1010
homepage: https://github.com/vorotynsky/HLasm#readme
1111
bug-reports: https://github.com/vorotynsky/HLasm/issues
@@ -27,7 +27,9 @@ executable Kroha
2727
other-modules:
2828
Kroha
2929
Kroha.Ast
30+
Kroha.Backends.Common
3031
Kroha.Backends.Nasm
32+
Kroha.Errors
3133
Kroha.Instructions
3234
Kroha.Parser
3335
Kroha.Scope

package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Kroha
2-
version: 1.0.0.0
2+
version: 1.1.0.0
33
github: "vorotynsky/HLasm"
44
license: GPL-3
55
author: "Vorotynsky Maxim"

src/Kroha.hs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
module Kroha where
22

3-
import Control.Monad.Zip (munzip, mzip)
4-
import Data.Bifunctor (first)
5-
import Data.Tree (Tree (..), drawTree)
3+
import Control.Monad.Zip (mzip)
4+
import Data.Bifunctor (first)
5+
import Data.Tree (Tree (..))
66

7-
import Kroha.Ast (FrameElement (..), selectorProg)
8-
import Kroha.Parser (parse)
9-
import Kroha.Scope (linkProgram, linksTree)
10-
import Kroha.Stack (stack)
11-
import Kroha.Types (resolve, typeCasts)
12-
import Kroha.Instructions(instructions)
13-
import Kroha.Backends.Nasm (runNasm)
7+
import Kroha.Parser (parse)
8+
import Kroha.Ast (FrameElement (Instructions), selectorProg)
9+
import Kroha.Scope (linkProgram, linksTree)
10+
import Kroha.Types (resolve, typeCastsTree, TypeConfig(..))
11+
import Kroha.Stack (stack)
12+
import Kroha.Instructions (instructions)
13+
import Kroha.Backends.Common (runBackend, Backend(typeConfig))
14+
import Kroha.Backends.Nasm (nasm)
1415

1516

1617
kroha :: String -> Either String String
17-
kroha src = compile
18+
kroha src = first show compile
1819
where compile = do
19-
program <- first id $ parse src
20-
scopes <- first show $ linkProgram program
20+
program <- parse src
21+
scopes <- linkProgram program
2122
let programTree = Node (Instructions []) (selectorProg (const $ Instructions []) id program)
22-
types <- first show $ resolve 16 . typeCasts $ mzip (linksTree program) scopes
23-
let stackRanges = stack 16 program
23+
let tc = (typeConfig nasm)
24+
casts <- (typeCastsTree tc $ mzip (linksTree program) scopes)
25+
types <- resolve tc casts
26+
let stackRanges = stack tc program
2427
let prepared = instructions stackRanges scopes program
25-
return (runNasm prepared)
28+
return (runBackend nasm prepared)

src/Kroha/Backends/Common.hs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module Kroha.Backends.Common (Backend(..), runBackend) where
2+
3+
import Kroha.Ast (Declaration(..))
4+
import Kroha.Types (TypeConfig)
5+
import Kroha.Instructions (Instruction(Body), Section)
6+
7+
import Control.Monad (join)
8+
import Data.Tree (Tree(..))
9+
import Data.Char (isSpace)
10+
import Data.Semigroup (Min(Min, getMin))
11+
12+
13+
data Backend = Backend
14+
{ typeConfig :: TypeConfig
15+
, instruction :: Instruction -> [String]
16+
, bodyWrap :: [String] -> [String]
17+
, indent :: String
18+
, section :: Section -> String -> String
19+
, declaration :: Declaration -> [String] -> String }
20+
21+
22+
makeFix :: Backend -> Tree [Instruction] -> [String]
23+
makeFix backend (Node i c) = join . fmap asmFix $ i
24+
where asmFix (Body _ i) = fmap ((++) (indent backend)) . bodyWrap backend $ makeFix backend (c !! i)
25+
asmFix i = instruction backend i
26+
27+
unindentManual :: String -> [String]
28+
unindentManual code = fmap (drop minIndent) lined
29+
where lined = let (h:t) = (\l -> if null l then [""] else l) $ lines code in if null h then t else h:t
30+
filterEmpty = filter (not . null . filter (not . isSpace))
31+
minIndent = getMin . foldMap (Min . length . takeWhile isSpace) . filterEmpty $ lined
32+
33+
backendDeclaration :: Backend -> Declaration -> Tree [Instruction] -> String
34+
backendDeclaration b decl@(Frame _ frame) ti = declaration b decl (makeFix b ti)
35+
backendDeclaration b decl@(GlobalVariable _ _ l) _ = declaration b decl []
36+
backendDeclaration b decl@(ConstantVariable _ _ l) _ = declaration b decl []
37+
backendDeclaration b decl@(ManualFrame _ c) _ = declaration b decl (unindentManual c)
38+
backendDeclaration b decl@(ManualVariable _ _ c) _ = declaration b decl (unindentManual c)
39+
40+
runBackend :: Backend -> [(Section, Declaration, Tree [Instruction])] -> String
41+
runBackend backend = join . fmap (mapper)
42+
where mapper (s, d, i) = section backend s (backendDeclaration backend d i)
43+

src/Kroha/Backends/Nasm.hs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
module Kroha.Backends.Nasm where
1+
module Kroha.Backends.Nasm (nasm) where
22

33
import Data.Tree
4+
import Data.Graph (buildG)
45
import Data.List (groupBy, intercalate)
56
import Control.Monad.Fix (fix)
67
import Control.Monad (join)
78
import Data.List.Extra (groupSort)
9+
import Data.Bifunctor (first)
810

911
import Kroha.Ast
10-
import Kroha.Instructions hiding (target)
12+
import Kroha.Backends.Common
13+
import Kroha.Types
14+
import Kroha.Instructions (Instruction(..), LabelTarget(..), Target(..), Section)
15+
import Kroha.Errors
1116

1217
bytes :: Int -> Int
1318
bytes x = ceiling ((toEnum x) / 8)
@@ -36,32 +41,37 @@ nasm16I (CallI l args) = (fmap (((++) "push ") . target) . reverse
3641
nasm16I (Jump l Nothing) = ["jmp " ++ label l]
3742
nasm16I (Jump lbl (Just (l, c, r))) = ["cmp " ++ target l ++ ", " ++ target r, jump c ++ " " ++ label lbl]
3843

39-
nasmBodyWrap body = body
40-
41-
makeFix :: Tree [Instruction] -> [String]
42-
makeFix (Node i c) = join . fmap asmFix $ i
43-
where asmFix (Body _ i) = fmap ((++) indent) . bodyWrap $ makeFix (c !! i)
44-
asmFix i = asm i
45-
(asm, indent, bodyWrap) = (nasm16I, " ", id)
46-
47-
nasmSection :: Section -> [[String]] -> String
48-
nasmSection section declarations = header <> body <> "\n\n"
44+
nasmSection :: Section -> String -> String
45+
nasmSection section body = header <> body <> "\n\n"
4946
where header = "section ." ++ section ++ "\n"
50-
body = intercalate "\n" . fmap (intercalate "\n") $ declarations
5147

5248
nasmType :: TypeName -> String
5349
nasmType (TypeName "int8" ) = "db"
5450
nasmType (TypeName "int16") = "dw"
5551

56-
nasmDeclaration :: Tree [Instruction] -> Declaration -> [String]
57-
nasmDeclaration t (Frame l _) = [l ++ ":"] ++ makeFix t ++ ["leave", "ret"]
58-
nasmDeclaration _ (GlobalVariable n t (IntegerLiteral l)) = [n ++ ": " ++ nasmType t ++ " " ++ show l]
59-
nasmDeclaration _ (ConstantVariable n t (IntegerLiteral l)) = [n ++ ": " ++ nasmType t ++ " " ++ show l]
60-
nasmDeclaration _ (ManualFrame l c) = [l ++ ":", c]
61-
nasmDeclaration _ (ManualVariable v _ c) = [v ++ ": " ++ c]
52+
nasmDeclaration :: Declaration -> [String] -> String
53+
nasmDeclaration (Frame l _) body = l ++ ":\n" ++ intercalate "\n" body ++ "\nleave\nret\n"
54+
nasmDeclaration (ManualVariable v _ _) [body] = v ++ ": " ++ body ++ "\n"
55+
nasmDeclaration (ManualFrame l _) body = l ++ ":\n" ++ intercalate "\n" (fmap ((++) " ") body)
56+
nasmDeclaration (ManualVariable v _ _) body = v ++ ":\n" ++ intercalate "\n" (fmap ((++) " ") body)
57+
nasmDeclaration (GlobalVariable n t (IntegerLiteral l)) _ = n ++ ": " ++ nasmType t ++ " " ++ show l
58+
nasmDeclaration (ConstantVariable n t (IntegerLiteral l)) _ = n ++ ": " ++ nasmType t ++ " " ++ show l
6259

60+
litType :: Literal -> Result TypeId
61+
litType l@(IntegerLiteral x) | x >= 0 && x < 65536 = Right 2
62+
| otherwise = Left (BackendError (show l ++ " is not in [0; 65536)"))
6363

64-
runNasm :: [(Section, Declaration, Tree [Instruction])] -> String
65-
runNasm = join . map mapper
66-
where mapper (s, d, t) = nasmSection s [nasmDeclaration t d]
64+
nasmTypes = TypeConfig
65+
{ types = (fmap . first) TypeName [("int8", 8), ("int16", 16), ("+literal+", 16)]
66+
, pointerType = 1
67+
, registers = zip (join $ fmap (\x -> fmap ((:) x . pure) "lhx") "abcd") (cycle [0, 0, 1])
68+
, typeCasts = buildG (0, 3) [(0, 2), (1, 2)]
69+
, literalType = litType }
6770

71+
nasm = Backend
72+
{ instruction = nasm16I
73+
, bodyWrap = id
74+
, indent = " "
75+
, section = nasmSection
76+
, declaration = nasmDeclaration
77+
, typeConfig = nasmTypes }

src/Kroha/Errors.hs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module Kroha.Errors where
2+
3+
import Kroha.Ast
4+
import Data.Bifunctor (bimap, first)
5+
import Data.Either (partitionEithers)
6+
import Data.Foldable (toList)
7+
import Data.List (intercalate)
8+
9+
type Result a = Either Error a
10+
11+
data Error
12+
= JoinedError [Error]
13+
| ParserError String
14+
| TypeCastError TypeName TypeName
15+
| UnknownType TypeName
16+
| UnknownRegister RegisterName
17+
| VariableNotFound VariableName
18+
| LabelNotFound Label
19+
| BackendError String
20+
21+
22+
instance Show Error where
23+
show (JoinedError errors) = intercalate "\n" $ fmap show errors
24+
show (ParserError message) = "[Parser error]:\n" ++ (unlines . fmap ((++) "\t") . lines) message
25+
show (TypeCastError t1 t2) = "[Type error]: " ++ "Can't cast from " ++ show t1 ++ " to " ++ show t2
26+
show (UnknownType t) = "[Type error]: " ++ "Unknown type " ++ show t
27+
show (UnknownRegister reg) = "[Type error]: " ++ "Unknown register name " ++ show reg
28+
show (VariableNotFound var) = "[Scope error]: " ++ "Variable " ++ var ++ " not found in the scope"
29+
show (LabelNotFound label) = "[Scope error]: " ++ "Label " ++ label ++ " not found in the scope"
30+
show (BackendError message) = "[Asm error]: \n" ++ (unlines . fmap ((++) "\t") . lines) message
31+
32+
firstE :: (a -> Error) -> Either a b -> Either Error b
33+
firstE = first
34+
35+
partitionErrors :: [Either a b] -> Either [a] [b]
36+
partitionErrors e = let (a, b) = partitionEithers e in if (null a) then Right b else Left a
37+
38+
sequenceErrors :: (Foldable f, Functor f) => ([a] -> c) -> f (Either a b) -> Either c (f b)
39+
sequenceErrors f e = bimap f (const g) $ partitionErrors (toList e)
40+
where g = fmap (\(Right x) -> x) e

src/Kroha/Parser.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
module Kroha.Parser (Kroha.Parser.parse) where
66

77
import Kroha.Ast
8+
import Kroha.Errors
89

910
import Data.Bifunctor (bimap)
1011
import Data.Maybe (maybeToList)
@@ -92,5 +93,5 @@ frame p = Frame <$> fname <*> block p
9293
globals = frame hlasm <|> constant <|> globvar <|> manualFrame <|> manualVar
9394
program = keyword "program" *> braces (many globals)
9495

95-
parse :: String -> Either String Program
96-
parse = bimap show Program . Text.Parsec.parse program ""
96+
parse :: String -> Result Program
97+
parse = bimap (ParserError . show) Program . Text.Parsec.parse program ""

src/Kroha/Scope.hs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module Kroha.Scope where
22

3-
import Control.Monad (join)
43
import Control.Monad.Zip (mzip, munzip, mzipWith)
54
import Data.Maybe (mapMaybe)
65
import Data.Tree (Tree(..))
6+
import Data.Bifunctor (first)
77

88
import Kroha.Ast
9+
import Kroha.Errors
910

1011
data ScopeEffect
1112
= FluentScope
@@ -62,12 +63,17 @@ scopeTree parent (Node effect childs) = Node (effect:parent) childScope
6263
where folder acc child = (rootLabel child : fst acc, snd acc ++ [scopeTree (fst acc) child])
6364
childScope = snd $ foldl folder (effect:parent, []) childs
6465

65-
linkScope :: Tree ([ScopeEffect], Scope) -> Either (ScopeEffect) (Tree Scope)
66-
linkScope (Node (request, scope) childs) = join . fmap buildTree $ results
67-
where results = traverse (\r -> findEither r scope >>= return . (,) r) request
68-
buildTree request = sequence . traverse (Node request) $ traverse linkScope childs
66+
linkScope :: Tree ([ScopeEffect], Scope) -> Result (Tree Scope)
67+
linkScope = sequenceErrors JoinedError . fmap (first scopeError . result)
68+
where result (request, scope) = traverse (\r -> findEither r scope >>= return . (,) r) request
69+
scopeError (VariableScope var) = VariableNotFound var
70+
scopeError (LabelScope label) = LabelNotFound label
6971

70-
linkProgram :: Program -> Either (ScopeEffect) (Tree Scope)
72+
declarationScope :: Program -> Scope
73+
declarationScope p@(Program declarations) = fmap (\(el, id) -> (dscope el, DeclarationLink el id)) $ zip declarations ids
74+
where ids = let (Node _ forest) = progId p in fmap rootLabel forest
75+
76+
linkProgram :: Program -> Result (Tree Scope)
7177
linkProgram program = linkScope (mzip requests scope)
7278
where (changes, requests) = munzip (localScope program)
73-
scope = scopeTree [] (mzip changes (linksTree program))
79+
scope = scopeTree (declarationScope program) (mzip changes (linksTree program))

src/Kroha/Stack.hs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,26 @@ module Kroha.Stack where
22

33
import Data.Tree
44
import Data.List (mapAccumL)
5+
import Data.Maybe (fromJust)
56

67
import Kroha.Ast
78
import Kroha.Types
89

910
type StackRange = (Int, Int) {-offset, size-}
1011

11-
stackVar :: PointerSize -> FrameElement -> Int
12-
stackVar ptr (VariableDeclaration (StackVariable _ t)) = typeSize ptr t
13-
stackVar _ _ = 0
12+
stackVar :: TypeConfig -> FrameElement -> Int
13+
stackVar tc (VariableDeclaration (StackVariable _ (PointerType _))) = snd $ types tc !! pointerType tc
14+
stackVar tc (VariableDeclaration (StackVariable _ t@(TypeName _))) = fromJust $ lookup t (types tc)
15+
stackVar _ _ = 0
1416

15-
frame :: PointerSize -> Tree FrameElement -> (Int, Tree StackRange)
17+
frame :: TypeConfig -> Tree FrameElement -> (Int, Tree StackRange)
1618
frame ptr tree = mapAccumL f 0 tree
1719
where f acc el = let size = stackVar ptr el in (acc + size, (if size > 0 then acc + size else 0, size))
1820

19-
stackFrames :: PointerSize -> Program -> [(Int, Tree StackRange)]
21+
stackFrames :: TypeConfig -> Program -> [(Int, Tree StackRange)]
2022
stackFrames ptr (Program declarations) = fmap mapper declarations
2123
where mapper (Frame _ f) = frame ptr (selector id f)
2224
mapper _ = (0, Node (0, 0) [])
2325

24-
stack :: PointerSize -> Program -> Tree StackRange
26+
stack :: TypeConfig -> Program -> Tree StackRange
2527
stack ptr program = Node (0, 0) (fmap (Node (0, 0) . pure . snd) (stackFrames ptr program))

0 commit comments

Comments
 (0)