Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5643aa703e | |||
| 74f68cb525 | |||
| f10f7883dd | |||
| a8c6a056da | |||
| c7796b4f25 | |||
| cc2d157674 | |||
| d576e64534 | |||
| cec34d1d9e | |||
| 69ae49a346 | |||
| e43a783d33 | |||
| 0496e6e1b4 | |||
| 4f5e4febdf | |||
| ffae200d3c | |||
| 85b93a604c | |||
| 3ffac1ffe6 | |||
| 3cf088b818 | |||
| e86389baf8 | |||
| 6aedcfe4e1 | |||
| fe71942a65 | |||
| a2ebe25901 | |||
| 8ac6223c6b | |||
| 9d4106aee8 | |||
| 95a80ca5d3 | |||
| b0abf5ee72 | |||
| 69b8bcba4d | |||
| 8ecda70a5f | |||
| 309d52715a | |||
| 0f2469f007 | |||
| bfd70838aa | |||
| e48012c3ed | |||
| fc2b31693d | |||
| 1bc9babd4f | |||
| 604db760ac | |||
| 4e24b2fb8a | |||
| 94e23b57fd | |||
| 22fd6733f0 | |||
| 62f42611bc | |||
| 2e601b86d5 | |||
| 2141bd44cb | |||
| 3ac33af1b5 | |||
| 9046e3621b | |||
| 7c0f49ccca | |||
| 6e16a502aa | |||
| b45502a550 | |||
| 83ff583c1c | |||
| f19d6f6d39 | |||
| cbd7df780a | |||
| 9d405fac61 | |||
| dde92cc64d | |||
| c8261b361a | |||
| d0d37dd05e | |||
| e8ab0ed082 | |||
| 544774d8b9 | |||
| f2cc603690 | |||
| a0f5d736f9 |
+4
-1
@@ -32,4 +32,7 @@ hie.yaml
|
||||
src/Grammar/Scanner.hs
|
||||
src/Grammar/Parser.hs
|
||||
src/Grammar/Parser.info
|
||||
src/Main
|
||||
src/Main
|
||||
out/
|
||||
mine.txt
|
||||
ref.txt
|
||||
@@ -0,0 +1,5 @@
|
||||
# use make build to compile all binaries
|
||||
build:
|
||||
alex ./src/Grammar/Scanner.x
|
||||
happy ./src/Grammar/Parser.y -o ./src/Grammar/Parser.hs
|
||||
ghc -dynamic -i./src src/Main.hs
|
||||
@@ -0,0 +1 @@
|
||||
public class Runner { public static void main(String[] args) { FieldsTest f = new FieldsTest(); System.out.println(f.b); } }
|
||||
+103
-3
@@ -3,15 +3,20 @@ module Codegen.ClassFile where
|
||||
import Codegen.ConstPool
|
||||
( generateConstPool,
|
||||
lookupClassIndex,
|
||||
lookupFieldRefIndex,
|
||||
lookupIntegerIndex,
|
||||
lookupUtf8Index,
|
||||
)
|
||||
import Codegen.Types
|
||||
import Data.Bits (shiftR, (.&.))
|
||||
import Data.Word (Word16, Word32, Word8)
|
||||
import Grammar.AST (Type)
|
||||
import Grammar.TAST
|
||||
( TypedClass (..),
|
||||
TypedExpr (..),
|
||||
TypedFieldDecl (..),
|
||||
TypedMethodDecl (..),
|
||||
TypedStmt (..),
|
||||
)
|
||||
|
||||
data ClassFile = ClassFile
|
||||
@@ -155,17 +160,112 @@ makeAttributes :: CP_Infos -> Attribute_Infos
|
||||
makeAttributes _ = []
|
||||
|
||||
makeMethods :: CP_Infos -> TypedClass -> Method_Infos
|
||||
makeMethods constPool (Class _ _ methods) = map (makeMethod constPool) methods
|
||||
makeMethods constPool (Class _ fields methods) =
|
||||
makeInitMethod constPool fields : map (makeMethod constPool) methods
|
||||
|
||||
makeInitMethod :: CP_Infos -> [TypedFieldDecl] -> Method_Info
|
||||
makeInitMethod constPool fields =
|
||||
Method_Info
|
||||
{ methodAccessFlags = AccessFlags [ACC_PUBLIC],
|
||||
methodNameIndex = lookupUtf8Index constPool "<init>",
|
||||
methodDescIndex = lookupUtf8Index constPool "()V",
|
||||
methodAttributes = [makeInitCode constPool fields]
|
||||
}
|
||||
|
||||
makeInitCode :: CP_Infos -> [TypedFieldDecl] -> Attribute_Info
|
||||
makeInitCode constPool fields =
|
||||
Code_Attribute
|
||||
{ codeNameIndex = lookupUtf8Index constPool "Code",
|
||||
maxStack = if null initFields then 1 else 2,
|
||||
maxLocals = 1,
|
||||
codeBody = [0x2A, 0xB7, 0x00, 0x08] ++ fieldInits ++ [0xB1],
|
||||
exceptionTable = [],
|
||||
codeAttributes = []
|
||||
}
|
||||
where
|
||||
initFields = [f | f@(Field _ _ (Just _)) <- fields]
|
||||
fieldInits = concatMap (fieldInitBytes constPool) initFields
|
||||
|
||||
fieldInitBytes :: CP_Infos -> TypedFieldDecl -> [Word8]
|
||||
fieldInitBytes constPool (Field _ name (Just expr)) =
|
||||
let idx = lookupFieldRefIndex constPool ("field ref: " ++ name)
|
||||
in [0x2A]
|
||||
++ pushExpr constPool expr
|
||||
++ [0xB5, fromIntegral (idx `shiftR` 8 .&. 0xFF), fromIntegral (idx .&. 0xFF)]
|
||||
fieldInitBytes _ _ = []
|
||||
|
||||
pushExpr :: CP_Infos -> TypedExpr -> [Word8]
|
||||
pushExpr constPool (Integer n _) = pushInt constPool (fromIntegral n)
|
||||
pushExpr _ (Bool True _) = [0x04]
|
||||
pushExpr _ (Bool False _) = [0x03]
|
||||
pushExpr constPool (Char c _) = pushInt constPool (fromEnum c)
|
||||
pushExpr _ (Null _) = [0x01]
|
||||
pushExpr _ _ = []
|
||||
|
||||
pushInt :: CP_Infos -> Int -> [Word8]
|
||||
pushInt constPool n
|
||||
| n >= -1 && n <= 5 = [fromIntegral (0x03 + n)]
|
||||
| n >= -128 && n <= 127 = [0x10, fromIntegral n]
|
||||
| n >= -32768 && n <= 32767 = [0x11, fromIntegral (n `shiftR` 8 .&. 0xFF), fromIntegral (n .&. 0xFF)]
|
||||
| otherwise =
|
||||
let idx = lookupIntegerIndex constPool n
|
||||
in if idx == 0
|
||||
then error $ "Missing Integer constant in pool: " ++ show n
|
||||
else
|
||||
if idx <= 255
|
||||
then [0x12, fromIntegral idx]
|
||||
else [0x13, fromIntegral (idx `shiftR` 8 .&. 0xFF), fromIntegral (idx .&. 0xFF)]
|
||||
|
||||
makeMethod :: CP_Infos -> TypedMethodDecl -> Method_Info
|
||||
makeMethod constPool (Method returnType name params _body) =
|
||||
makeMethod constPool (Method returnType name params body) =
|
||||
Method_Info
|
||||
{ methodAccessFlags = AccessFlags [ACC_PUBLIC],
|
||||
methodNameIndex = lookupUtf8Index constPool name,
|
||||
methodDescIndex = lookupUtf8Index constPool (methodDescriptor params returnType),
|
||||
methodAttributes = []
|
||||
methodAttributes = [makeMethodCode constPool returnType params body]
|
||||
}
|
||||
|
||||
makeMethodCode :: CP_Infos -> Type -> [(Type, String)] -> TypedStmt -> Attribute_Info
|
||||
makeMethodCode constPool returnType params body =
|
||||
let (code, stack) = stmtCode constPool returnType body
|
||||
locals = 1 + length params
|
||||
in Code_Attribute
|
||||
{ codeNameIndex = lookupUtf8Index constPool "Code",
|
||||
maxStack = stack,
|
||||
maxLocals = locals,
|
||||
codeBody = code,
|
||||
exceptionTable = [],
|
||||
codeAttributes = []
|
||||
}
|
||||
|
||||
stmtCode :: CP_Infos -> Type -> TypedStmt -> ([Word8], Int)
|
||||
stmtCode constPool returnType stmt = case stmt of
|
||||
Return Nothing _
|
||||
| returnType == "void" -> ([0xB1], 0)
|
||||
| otherwise -> error "Non-void method must return a value"
|
||||
Return (Just expr) _ ->
|
||||
let (exprBytes, stack) = exprCode constPool expr
|
||||
retOp = case returnType of
|
||||
"int" -> 0xAC
|
||||
"boolean" -> 0xAC
|
||||
"char" -> 0xAC
|
||||
_ -> error $ "Unsupported return type: " ++ returnType
|
||||
in (exprBytes ++ [retOp], stack)
|
||||
Block [single] _ -> stmtCode constPool returnType single
|
||||
Block [] _
|
||||
| returnType == "void" -> ([0xB1], 0)
|
||||
| otherwise -> error "Non-void method must return a value"
|
||||
_ -> error "Unsupported method body"
|
||||
|
||||
exprCode :: CP_Infos -> TypedExpr -> ([Word8], Int)
|
||||
exprCode constPool expr = case expr of
|
||||
Integer n _ -> (pushInt constPool (fromIntegral n), 1)
|
||||
Bool True _ -> ([0x04], 1)
|
||||
Bool False _ -> ([0x03], 1)
|
||||
Char c _ -> (pushInt constPool (fromEnum c), 1)
|
||||
Null _ -> ([0x01], 1)
|
||||
_ -> error "Unsupported return expression"
|
||||
|
||||
methodDescriptor :: [(Type, String)] -> Type -> String
|
||||
methodDescriptor params returnType =
|
||||
"(" ++ concatMap (typeDescriptor . fst) params ++ ")" ++ typeDescriptor returnType
|
||||
|
||||
+164
-24
@@ -1,7 +1,7 @@
|
||||
module Codegen.ConstPool where
|
||||
|
||||
import Codegen.Types
|
||||
import Data.List (isSuffixOf)
|
||||
import Data.List (isPrefixOf, isSuffixOf)
|
||||
import qualified Grammar.TAST as TAST
|
||||
|
||||
------------------------------------------------------------------------
|
||||
@@ -89,6 +89,18 @@ collectFromExprs :: [TAST.TypedExpr] -> CP_Infos
|
||||
collectFromExprs [] = []
|
||||
collectFromExprs (e : es) = collectFromTypedExpr e ++ collectFromExprs es
|
||||
|
||||
exprType :: TAST.TypedExpr -> String
|
||||
exprType (TAST.This t) = t
|
||||
exprType (TAST.LocalOrFieldVar _ t) = t
|
||||
exprType (TAST.InstVar _ _ t) = t
|
||||
exprType (TAST.Unary _ _ t) = t
|
||||
exprType (TAST.Binary _ _ _ t) = t
|
||||
exprType (TAST.Integer _ t) = t
|
||||
exprType (TAST.Bool _ t) = t
|
||||
exprType (TAST.Char _ t) = t
|
||||
exprType (TAST.Null t) = t
|
||||
exprType (TAST.StmtExprExpr _ t) = t
|
||||
|
||||
collectFromTypedExpr :: TAST.TypedExpr -> CP_Infos
|
||||
collectFromTypedExpr (TAST.Integer n _) =
|
||||
[mkIntegerInfo (fromIntegral n) ("int " ++ show n)]
|
||||
@@ -103,12 +115,14 @@ collectFromTypedExpr (TAST.This _) =
|
||||
collectFromTypedExpr (TAST.LocalOrFieldVar _ _) =
|
||||
[]
|
||||
collectFromTypedExpr (TAST.InstVar obj name typ) =
|
||||
collectFromTypedExpr obj
|
||||
++ [ mkUtf8Info name ("field name: " ++ name),
|
||||
mkUtf8Info (typeToDescriptor typ) ("field descriptor: " ++ typeToDescriptor typ),
|
||||
mkNameAndTypeInfo 0 0 ("field NameAndType: " ++ name),
|
||||
mkFieldRefInfo 0 0 ("field ref: " ++ name)
|
||||
]
|
||||
let objType = exprType obj
|
||||
desc = typeToDescriptor typ
|
||||
in collectFromTypedExpr obj
|
||||
++ [ mkUtf8Info name ("field name: " ++ name),
|
||||
mkUtf8Info desc ("field descriptor: " ++ desc),
|
||||
mkNameAndTypeInfo 0 0 ("field NameAndType: " ++ name ++ ":" ++ desc),
|
||||
mkFieldRefInfo 0 0 ("field ref: " ++ objType ++ "." ++ name ++ ":" ++ desc)
|
||||
]
|
||||
collectFromTypedExpr (TAST.Unary _ e _) =
|
||||
collectFromTypedExpr e
|
||||
collectFromTypedExpr (TAST.Binary _ e1 e2 _) =
|
||||
@@ -122,16 +136,20 @@ collectFromTypedStmtExpr (TAST.Assign lhs rhs _) =
|
||||
collectFromTypedStmtExpr (TAST.New t args _) =
|
||||
collectFromExprs args
|
||||
++ [ mkUtf8Info t ("class name: " ++ t),
|
||||
mkClassInfo 0 ("class: " ++ t)
|
||||
mkClassInfo 0 ("class: " ++ t),
|
||||
mkMethodRefInfo 0 0 ("new method ref: " ++ t ++ ".<init>:()V")
|
||||
]
|
||||
collectFromTypedStmtExpr (TAST.MethodCall obj name args retTyp) =
|
||||
collectFromTypedExpr obj
|
||||
++ collectFromExprs args
|
||||
++ [ mkUtf8Info name ("method name: " ++ name),
|
||||
mkUtf8Info (typeToDescriptor retTyp) ("method ret desc: " ++ typeToDescriptor retTyp),
|
||||
mkNameAndTypeInfo 0 0 ("method NameAndType: " ++ name),
|
||||
mkMethodRefInfo 0 0 ("method ref: " ++ name)
|
||||
]
|
||||
let objType = exprType obj
|
||||
argTypes = map exprType args
|
||||
fullDesc = "(" ++ concatMap typeToDescriptor argTypes ++ ")" ++ typeToDescriptor retTyp
|
||||
in collectFromTypedExpr obj
|
||||
++ collectFromExprs args
|
||||
++ [ mkUtf8Info name ("method name: " ++ name),
|
||||
mkUtf8Info fullDesc ("method desc: " ++ name),
|
||||
mkNameAndTypeInfo 0 0 ("method NameAndType: " ++ name ++ ":" ++ fullDesc),
|
||||
mkMethodRefInfo 0 0 ("method ref: " ++ objType ++ "." ++ name ++ ":" ++ fullDesc)
|
||||
]
|
||||
|
||||
collectFromStmts :: [TAST.TypedStmt] -> CP_Infos
|
||||
collectFromStmts [] = []
|
||||
@@ -154,6 +172,8 @@ collectFromTypedStmt (TAST.If cond then_ mElse _) =
|
||||
++ collectFromMaybeStmt mElse
|
||||
collectFromTypedStmt (TAST.StmtExprStmt se _) =
|
||||
collectFromTypedStmtExpr se
|
||||
collectFromTypedStmt (TAST.EmptyStmt _) =
|
||||
[]
|
||||
|
||||
collectFromMaybeStmt :: Maybe TAST.TypedStmt -> CP_Infos
|
||||
collectFromMaybeStmt Nothing = []
|
||||
@@ -161,9 +181,8 @@ collectFromMaybeStmt (Just s) = collectFromTypedStmt s
|
||||
|
||||
collectFromFields :: [TAST.TypedFieldDecl] -> CP_Infos
|
||||
collectFromFields [] = []
|
||||
collectFromFields (TAST.Field fType fName _: fs ) =
|
||||
collectFromFields (TAST.Field fType fName _ : fs) =
|
||||
[ mkUtf8Info fName ("field: " ++ fName),
|
||||
|
||||
mkUtf8Info (typeToDescriptor fType) ("field desc: " ++ fType)
|
||||
]
|
||||
++ collectFromFields fs
|
||||
@@ -183,13 +202,43 @@ collectFromMethods (TAST.Method mType mName params body : ms) =
|
||||
|
||||
generateConstPool :: TAST.TypedClass -> CP_Infos
|
||||
generateConstPool (TAST.Class cName fields methods) =
|
||||
[ mkUtf8Info cName ("this class: " ++ cName),
|
||||
mkUtf8Info "java/lang/Object" "super class",
|
||||
mkClassInfo 0 ("this class: " ++ cName),
|
||||
mkClassInfo 0 "super class"
|
||||
]
|
||||
++ collectFromFields fields
|
||||
++ collectFromMethods methods
|
||||
let basePool =
|
||||
[ mkUtf8Info cName ("this class: " ++ cName), -- #1
|
||||
mkUtf8Info "java/lang/Object" "super class", -- #2
|
||||
mkClassInfo 1 ("this class: " ++ cName), -- #3 → #1
|
||||
mkClassInfo 2 "super class", -- #4 → #2
|
||||
mkUtf8Info "<init>" "<init>", -- #5
|
||||
mkUtf8Info "()V" "init descriptor", -- #6
|
||||
mkNameAndTypeInfo 5 6 "<init>:()V", -- #7
|
||||
mkMethodRefInfo 4 7 "java/lang/Object.<init>:()V", -- #8
|
||||
mkUtf8Info "Code" "Code" -- #9
|
||||
]
|
||||
++ collectFromFields fields
|
||||
++ buildInitFieldPool fields (length fields)
|
||||
initExprs = [e | TAST.Field _ _ (Just e) <- fields]
|
||||
initPool = concatMap collectFromTypedExpr initExprs
|
||||
methodPool = collectFromMethods methods
|
||||
rawPool = basePool ++ initPool ++ methodPool
|
||||
in resolvePool rawPool
|
||||
|
||||
-- Build NameAndType + Fieldref entries for each field with an initializer.
|
||||
-- The base pool has 9 fixed entries; collectFromFields adds 2 per field.
|
||||
-- So for field at 0-based index i: name Utf8 = #(9 + 2i + 1), desc = #(9 + 2i + 2).
|
||||
-- NameAndType entries follow at #(9 + 2*numFields + 2j + 1) for j-th init field.
|
||||
buildInitFieldPool :: [TAST.TypedFieldDecl] -> Int -> CP_Infos
|
||||
buildInitFieldPool fields numFields = go 0 0 fields
|
||||
where
|
||||
go _ _ [] = []
|
||||
go fieldIdx initIdx (TAST.Field _ _ Nothing : rest) =
|
||||
go (fieldIdx + 1) initIdx rest
|
||||
go fieldIdx initIdx (TAST.Field _ name _ : rest) =
|
||||
let nameUtf8Idx = 9 + 2 * fieldIdx + 1
|
||||
descUtf8Idx = 9 + 2 * fieldIdx + 2
|
||||
natCpIdx = 9 + 2 * numFields + 2 * initIdx + 1
|
||||
in [ mkNameAndTypeInfo nameUtf8Idx descUtf8Idx ("field NameAndType: " ++ name),
|
||||
mkFieldRefInfo 3 natCpIdx ("field ref: " ++ name)
|
||||
]
|
||||
++ go (fieldIdx + 1) (initIdx + 1) rest
|
||||
|
||||
lookupClassIndex :: CP_Infos -> String -> IndexConstantPool
|
||||
lookupClassIndex pool name =
|
||||
@@ -223,6 +272,97 @@ lookupNameAndTypeIndex pool name =
|
||||
NameAndTypeInfo {desc = descVal} -> descVal == name || isSuffixOf name descVal
|
||||
_ -> False
|
||||
|
||||
lookupFieldRefIndex :: CP_Infos -> String -> IndexConstantPool
|
||||
lookupFieldRefIndex pool name =
|
||||
case findIndex matches pool of
|
||||
Just i -> i
|
||||
Nothing -> 0
|
||||
where
|
||||
matches entry = case entry of
|
||||
FieldRefInfo {desc = descVal} -> descVal == name || isSuffixOf name descVal
|
||||
_ -> False
|
||||
|
||||
lookupMethodRefIndex :: CP_Infos -> String -> IndexConstantPool
|
||||
lookupMethodRefIndex pool name =
|
||||
case findIndex matches pool of
|
||||
Just i -> i
|
||||
Nothing -> 0
|
||||
where
|
||||
matches entry = case entry of
|
||||
MethodRefInfo {desc = descVal} -> descVal == name || isSuffixOf name descVal
|
||||
_ -> False
|
||||
|
||||
lookupIntegerIndex :: CP_Infos -> Int -> IndexConstantPool
|
||||
lookupIntegerIndex pool value =
|
||||
case findIndex matches pool of
|
||||
Just i -> i
|
||||
Nothing -> 0
|
||||
where
|
||||
matches entry = case entry of
|
||||
IntegerInfo {numi_cp = n} -> n == value
|
||||
_ -> False
|
||||
|
||||
resolvePool :: CP_Infos -> CP_Infos
|
||||
resolvePool pool = map resolveEntry pool
|
||||
where
|
||||
resolveEntry (ClassInfo tag 0 desc) =
|
||||
ClassInfo tag (lookupUtf8Index pool (classNameFromDesc desc)) desc
|
||||
resolveEntry (NameAndTypeInfo tag 0 0 desc) =
|
||||
let (name, descr) = nameAndTypeFromDesc desc
|
||||
nameIdx = lookupUtf8Index pool name
|
||||
descIdx = lookupUtf8Index pool descr
|
||||
in NameAndTypeInfo tag nameIdx descIdx desc
|
||||
resolveEntry (FieldRefInfo tag 0 0 desc) =
|
||||
let (clsName, natDesc) = fieldRefFromDesc desc
|
||||
clsIdx = if null clsName then 0 else lookupClassIndex pool clsName
|
||||
natIdx = if null natDesc then 0 else lookupNameAndTypeIndex pool natDesc
|
||||
in FieldRefInfo tag clsIdx natIdx desc
|
||||
resolveEntry (MethodRefInfo tag 0 0 desc) =
|
||||
let (clsName, natDesc) = methodRefFromDesc desc
|
||||
clsIdx = if null clsName then 0 else lookupClassIndex pool clsName
|
||||
natIdx = if null natDesc then 0 else lookupNameAndTypeIndex pool natDesc
|
||||
in MethodRefInfo tag clsIdx natIdx desc
|
||||
resolveEntry other = other
|
||||
|
||||
classNameFromDesc :: String -> String
|
||||
classNameFromDesc desc
|
||||
| "class: " `isPrefixOf` desc = drop 7 desc
|
||||
| "this class: " `isPrefixOf` desc = drop 12 desc
|
||||
| desc == "super class" = "java/lang/Object"
|
||||
| otherwise = desc
|
||||
|
||||
nameAndTypeFromDesc :: String -> (String, String)
|
||||
nameAndTypeFromDesc desc
|
||||
| "field NameAndType: " `isPrefixOf` desc =
|
||||
let rest = drop 19 desc
|
||||
(name, descPart) = break (== ':') rest
|
||||
in (name, drop 1 descPart)
|
||||
| "method NameAndType: " `isPrefixOf` desc =
|
||||
let rest = drop 20 desc
|
||||
(name, descPart) = break (== ':') rest
|
||||
in (name, drop 1 descPart)
|
||||
| otherwise = ("", "")
|
||||
|
||||
fieldRefFromDesc :: String -> (String, String)
|
||||
fieldRefFromDesc desc
|
||||
| "field ref: " `isPrefixOf` desc =
|
||||
let rest = drop 11 desc
|
||||
(clsName, natDesc') = break (== '.') rest
|
||||
in (clsName, drop 1 natDesc')
|
||||
| otherwise = ("", "")
|
||||
|
||||
methodRefFromDesc :: String -> (String, String)
|
||||
methodRefFromDesc desc
|
||||
| "new method ref: " `isPrefixOf` desc =
|
||||
let rest = drop 16 desc
|
||||
(clsName, natDesc') = break (== '.') rest
|
||||
in (clsName, drop 1 natDesc')
|
||||
| "method ref: " `isPrefixOf` desc =
|
||||
let rest = drop 12 desc
|
||||
(clsName, natDesc') = break (== '.') rest
|
||||
in (clsName, drop 1 natDesc')
|
||||
| otherwise = ("", "")
|
||||
|
||||
findIndex :: (CP_Info -> Bool) -> CP_Infos -> Maybe IndexConstantPool
|
||||
findIndex predicate pool = go 1 pool
|
||||
where
|
||||
|
||||
+34
-2
@@ -1,7 +1,7 @@
|
||||
module Codegen.Lowerer where
|
||||
|
||||
import Codegen.ClassFile
|
||||
import Codegen.Types (CP_Info (Utf8Info), CP_Infos)
|
||||
import Codegen.Types (CP_Info (..), CP_Infos)
|
||||
import Data.Word (Word8)
|
||||
import Numeric (showHex)
|
||||
|
||||
@@ -17,13 +17,20 @@ data Instruction
|
||||
| InvokeVirtual Int
|
||||
| InvokeStatic Int
|
||||
| IConst Int
|
||||
| BIPush Int
|
||||
| SIPush Int
|
||||
| AConstNull
|
||||
| Ldc Int
|
||||
| IAdd
|
||||
| ISub
|
||||
| IMul
|
||||
| IDiv
|
||||
| IfEq Int
|
||||
| IfNe Int
|
||||
| IfLt Int
|
||||
| IfGe Int
|
||||
| IfGt Int
|
||||
| IfLe Int
|
||||
| Goto Int
|
||||
| Return
|
||||
| IReturn
|
||||
@@ -108,13 +115,20 @@ decodeBytes pos (b : bs) = case b of
|
||||
0x07 -> line (IConst 4) pos 1 bs
|
||||
0x08 -> line (IConst 5) pos 1 bs
|
||||
0x01 -> line AConstNull pos 1 bs
|
||||
0x10 -> withSignedByte bs pos $ \n rest -> line (BIPush n) pos 2 rest
|
||||
0x11 -> withSignedShort bs pos $ \n rest -> line (SIPush n) pos 3 rest
|
||||
0x12 -> withByte bs pos $ \i rest -> line (Ldc i) pos 2 rest
|
||||
0x13 -> withIndex bs pos $ \i rest -> line (Ldc i) pos 3 rest
|
||||
0x60 -> line IAdd pos 1 bs
|
||||
0x64 -> line ISub pos 1 bs
|
||||
0x68 -> line IMul pos 1 bs
|
||||
0x6C -> line IDiv pos 1 bs
|
||||
0x99 -> withIndex bs pos $ \i rest -> line (IfEq i) pos 3 rest
|
||||
0x9A -> withIndex bs pos $ \i rest -> line (IfNe i) pos 3 rest
|
||||
0x9B -> withIndex bs pos $ \i rest -> line (IfLt i) pos 3 rest
|
||||
0x9C -> withIndex bs pos $ \i rest -> line (IfGe i) pos 3 rest
|
||||
0x9D -> withIndex bs pos $ \i rest -> line (IfGt i) pos 3 rest
|
||||
0x9E -> withIndex bs pos $ \i rest -> line (IfLe i) pos 3 rest
|
||||
0xA7 -> withIndex bs pos $ \i rest -> line (Goto i) pos 3 rest
|
||||
0xB1 -> line Return pos 1 bs
|
||||
0xAC -> line IReturn pos 1 bs
|
||||
@@ -133,7 +147,25 @@ withIndex :: [Word8] -> Int -> (Int -> [Word8] -> [BtcLine]) -> [BtcLine]
|
||||
withIndex (hi : lo : rest) _ f = f (fromIntegral hi * 256 + fromIntegral lo) rest
|
||||
withIndex _ pos _ = error $ "Unexpected end of bytecode at " ++ show pos
|
||||
|
||||
withSignedByte :: [Word8] -> Int -> (Int -> [Word8] -> [BtcLine]) -> [BtcLine]
|
||||
withSignedByte (b : rest) _ f = f (signedByte b) rest
|
||||
withSignedByte [] pos _ = error $ "Unexpected end of bytecode at " ++ show pos
|
||||
|
||||
withSignedShort :: [Word8] -> Int -> (Int -> [Word8] -> [BtcLine]) -> [BtcLine]
|
||||
withSignedShort (hi : lo : rest) _ f = f (signedShort hi lo) rest
|
||||
withSignedShort _ pos _ = error $ "Unexpected end of bytecode at " ++ show pos
|
||||
|
||||
signedByte :: Word8 -> Int
|
||||
signedByte b =
|
||||
let n = fromIntegral b :: Int
|
||||
in if n >= 128 then n - 256 else n
|
||||
|
||||
signedShort :: Word8 -> Word8 -> Int
|
||||
signedShort hi lo =
|
||||
let n = fromIntegral hi * 256 + fromIntegral lo :: Int
|
||||
in if n >= 32768 then n - 65536 else n
|
||||
|
||||
lookupPool :: CP_Infos -> Index -> Maybe CP_Info
|
||||
lookupPool pool i
|
||||
| i < 1 || i > length pool = Nothing
|
||||
| otherwise = Just (pool !! (i - 1)) -- pool is 1-indexed
|
||||
| otherwise = Just (pool !! (i - 1)) -- pool is 1-indexed
|
||||
@@ -1,7 +1,11 @@
|
||||
module Codegen.Serializer where
|
||||
|
||||
import Data.Bits (shiftR, (.&.))
|
||||
import Data.Word (Word8)
|
||||
import Codegen.ClassFile
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
import Codegen.Types
|
||||
import Data.Bits (shiftR, (.&.), (.|.))
|
||||
import Data.Char (ord)
|
||||
import Data.Word (Word16, Word32, Word8)
|
||||
|
||||
-- Split a 16-bit Int into two bytes (big-endian), as JVM expects
|
||||
indexBytes :: Int -> [Word8]
|
||||
@@ -54,6 +58,13 @@ serializeInstruction instr = case instr of
|
||||
IConst 4 -> [0x07]
|
||||
IConst 5 -> [0x08]
|
||||
IConst n -> error $ "IConst out of range (-1..5): " ++ show n
|
||||
-- bipush/sipush: push signed byte/short
|
||||
BIPush n
|
||||
| n >= -128 && n <= 127 -> [0x10, fromIntegral n]
|
||||
| otherwise -> error $ "BIPush out of range (-128..127): " ++ show n
|
||||
SIPush n
|
||||
| n >= -32768 && n <= 32767 -> 0x11 : indexBytes (n .&. 0xFFFF)
|
||||
| otherwise -> error $ "SIPush out of range (-32768..32767): " ++ show n
|
||||
AConstNull -> [0x01]
|
||||
-- ldc: 1-byte index (use ldc_w 0x13 for large pool indices > 255)
|
||||
Ldc i
|
||||
@@ -64,9 +75,14 @@ serializeInstruction instr = case instr of
|
||||
IAdd -> [0x60]
|
||||
ISub -> [0x64]
|
||||
IMul -> [0x68]
|
||||
IDiv -> [0x6C]
|
||||
-- Control flow: 2-byte signed branch offset
|
||||
IfEq offset -> 0x99 : indexBytes offset
|
||||
IfNe offset -> 0x9A : indexBytes offset
|
||||
IfLt offset -> 0x9B : indexBytes offset
|
||||
IfGe offset -> 0x9C : indexBytes offset
|
||||
IfGt offset -> 0x9D : indexBytes offset
|
||||
IfLe offset -> 0x9E : indexBytes offset
|
||||
Goto offset -> 0xA7 : indexBytes offset
|
||||
-- Return
|
||||
Return -> [0xB1]
|
||||
@@ -77,3 +93,72 @@ serializeInstruction instr = case instr of
|
||||
serializeProgram :: BtcProgram -> [Word8]
|
||||
serializeProgram (BtcProgram lines) =
|
||||
concatMap (serializeInstruction . instruction) lines
|
||||
|
||||
serializeClassFile :: ClassFile -> [Word8]
|
||||
serializeClassFile cf =
|
||||
u4 (let Magic m = magic cf in m)
|
||||
++ u2 (let MinorVersion v = minorVersion cf in v)
|
||||
++ u2 (let MajorVersion v = majorVersion cf in v)
|
||||
++ u2 (length (constantPool cf) + 1)
|
||||
++ concatMap cpEntry (constantPool cf)
|
||||
++ aflags (accessFlags cf)
|
||||
++ u2 (let ThisClass i = thisClass cf in i)
|
||||
++ u2 (let SuperClass i = superClass cf in i)
|
||||
++ u2 (length (interfaces cf))
|
||||
++ concatMap (\i -> u2 (fromIntegral (i :: Word16) :: Int)) (interfaces cf)
|
||||
++ u2 (length (fields cf))
|
||||
++ concatMap fieldEntry (fields cf)
|
||||
++ u2 (length (methods cf))
|
||||
++ concatMap methodEntry (methods cf)
|
||||
++ u2 (length (attributes cf))
|
||||
++ concatMap attrEntry (attributes cf)
|
||||
where
|
||||
u2 :: Int -> [Word8]
|
||||
u2 n = [fromIntegral ((n `shiftR` 8) .&. 0xFF), fromIntegral (n .&. 0xFF)]
|
||||
u4 :: (Integral a) => a -> [Word8]
|
||||
u4 n =
|
||||
let w = fromIntegral n :: Word32
|
||||
in map (\s -> fromIntegral ((w `shiftR` s) .&. 0xFF)) [24, 16, 8, 0]
|
||||
aflags (AccessFlags fs) = u2 (foldr (\f a -> a .|. fval f) (0 :: Int) fs)
|
||||
fval :: AccessFlag -> Int
|
||||
fval ACC_PUBLIC = 0x0001
|
||||
fval ACC_PRIVATE = 0x0002
|
||||
fval ACC_PROTECTED = 0x0004
|
||||
fval ACC_STATIC = 0x0008
|
||||
fval ACC_FINAL = 0x0010
|
||||
fval ACC_SUPER = 0x0020
|
||||
fval ACC_INTERFACE = 0x0200
|
||||
fval ACC_ABSTRACT = 0x0400
|
||||
fval ACC_SYNTHETIC = 0x1000
|
||||
fval ACC_ENUM = 0x4000
|
||||
cpEntry (Utf8Info _ _ s _) = [1] ++ u2 (length s) ++ map (fromIntegral . ord) s
|
||||
cpEntry (ClassInfo _ i _) = [7] ++ u2 i
|
||||
cpEntry (FieldRefInfo _ c n _) = [9] ++ u2 c ++ u2 n
|
||||
cpEntry (MethodRefInfo _ c n _) = [10] ++ u2 c ++ u2 n
|
||||
cpEntry (StringInfo _ i _) = [8] ++ u2 i
|
||||
cpEntry (IntegerInfo _ v _) = [3] ++ u4 v
|
||||
cpEntry (NameAndTypeInfo _ n d _) = [12] ++ u2 n ++ u2 d
|
||||
fieldEntry fi =
|
||||
aflags (fieldAccessFlags fi)
|
||||
++ u2 (fieldNameIndex fi)
|
||||
++ u2 (fieldDescIndex fi)
|
||||
++ u2 (0 :: Int)
|
||||
methodEntry mi =
|
||||
aflags (methodAccessFlags mi)
|
||||
++ u2 (methodNameIndex mi)
|
||||
++ u2 (methodDescIndex mi)
|
||||
++ u2 (length (methodAttributes mi))
|
||||
++ concatMap attrEntry (methodAttributes mi)
|
||||
attrEntry (Code_Attribute ni ms ml code exc ca) =
|
||||
let body =
|
||||
u2 ms
|
||||
++ u2 ml
|
||||
++ u4 (length code)
|
||||
++ code
|
||||
++ u2 (length exc)
|
||||
++ concatMap excEntry exc
|
||||
++ u2 (length ca)
|
||||
++ concatMap attrEntry ca
|
||||
in u2 ni ++ u4 (length body) ++ body
|
||||
attrEntry (Generic_Attribute ni dat) = u2 ni ++ u4 (length dat) ++ dat
|
||||
excEntry e = u2 (startPc e) ++ u2 (endPc e) ++ u2 (handlerPc e) ++ u2 (catchType e)
|
||||
|
||||
+2
-1
@@ -33,9 +33,10 @@ data Stmt
|
||||
= Block [Stmt]
|
||||
| Return (Maybe Expr)
|
||||
| While Expr Stmt
|
||||
| LocalVarDecl Type String
|
||||
| LocalVarDecl Type String (Maybe Expr)
|
||||
| If Expr Stmt (Maybe Stmt)
|
||||
| StmtExprStmt StmtExpr
|
||||
| EmptyStmt
|
||||
deriving (Show, Eq)
|
||||
|
||||
data BinaryOperator
|
||||
|
||||
+24
-8
@@ -17,9 +17,11 @@ import Grammar.AST
|
||||
return { TokenReturn }
|
||||
new { TokenNew }
|
||||
this { TokenThis }
|
||||
null { TokenNull }
|
||||
if { TokenIf }
|
||||
else { TokenElse }
|
||||
while { TokenWhile }
|
||||
for { TokenFor }
|
||||
int { TokenIntType }
|
||||
boolean { TokenBoolType }
|
||||
char { TokenCharType }
|
||||
@@ -90,6 +92,9 @@ MethodDecl : Type id '(' Params ')' Block { Method $1 $2 $4 $6 }
|
||||
| void id '(' Params ')' Block { Method "void" $2 $4 $6 }
|
||||
| public void id '(' Params ')' Block { Method "void" $3 $5 $7 }
|
||||
| private void id '(' Params ')' Block { Method "void" $3 $5 $7 }
|
||||
| id '(' Params ')' Block { Method "void" "<init>" $3 $5 }
|
||||
| private id '(' Params ')' Block { Method "void" "<init>" $4 $6 }
|
||||
| public id '(' Params ')' Block { Method "void" "<init>" $4 $6 }
|
||||
|
||||
Params : ParamList { $1 }
|
||||
| {- leer -} { [] }
|
||||
@@ -109,19 +114,29 @@ Block : '{' Stmts '}' { Block (reverse $2) }
|
||||
Stmts : Stmts Stmt { $2 : $1 }
|
||||
| {- leer -} { [] }
|
||||
|
||||
Stmt : Block { $1 }
|
||||
| return Expr ';' { Return (Just $2) }
|
||||
| return ';' { Return Nothing }
|
||||
| while '(' Expr ')' Stmt { While $3 $5 }
|
||||
| if '(' Expr ')' Stmt else Stmt { If $3 $5 (Just $7) }
|
||||
| if '(' Expr ')' Stmt { If $3 $5 Nothing }
|
||||
| Type id ';' { LocalVarDecl $1 $2 }
|
||||
| StmtExpr ';' { StmtExprStmt $1 }
|
||||
|
||||
Stmt : Block { $1 }
|
||||
| return Expr ';' { Return (Just $2) }
|
||||
| return ';' { Return Nothing }
|
||||
| while '(' Expr ')' Stmt { While $3 $5 }
|
||||
| for '(' Stmt Expr ';' StmtExpr ')' Stmt { Block [$3, (While $4 (Block [$8, (StmtExprStmt $6)]))] }
|
||||
| for '(' Stmt Expr ';' ')' Stmt { Block [$3, (While $4 $7)] }
|
||||
| if '(' Expr ')' Stmt else Stmt { If $3 $5 (Just $7) }
|
||||
| if '(' Expr ')' Stmt { If $3 $5 Nothing }
|
||||
| Type id ';' { LocalVarDecl $1 $2 Nothing }
|
||||
| Type id '=' Expr ';' { LocalVarDecl $1 $2 (Just $4) }
|
||||
| StmtExpr ';' { StmtExprStmt $1 }
|
||||
| ';' { EmptyStmt }
|
||||
|
||||
StmtExpr : Expr '=' Expr { Assign $1 $3 }
|
||||
| new id '(' Exprs ')' { New $2 $4 }
|
||||
| Expr '.' id '(' Exprs ')' { MethodCall $1 $3 $5 }
|
||||
| id '(' Exprs ')' { MethodCall This $1 $3 }
|
||||
| Expr '+' '=' Expr { Assign $1 (Binary Add $1 $4) }
|
||||
| Expr '-' '=' Expr { Assign $1 (Binary Subtract $1 $4) }
|
||||
| Expr '*' '=' Expr { Assign $1 (Binary Multiply $1 $4) }
|
||||
| Expr '/' '=' Expr { Assign $1 (Binary Divide $1 $4) }
|
||||
| Expr '%' '=' Expr { Assign $1 (Binary Modulo $1 $4) }
|
||||
|
||||
Expr : this { This }
|
||||
| id { LocalOrFieldVar $1 }
|
||||
@@ -129,6 +144,7 @@ Expr : this { This }
|
||||
| intLit { Integer $1 }
|
||||
| boolLit { Bool $1 }
|
||||
| charLit { Char $1 }
|
||||
| null { Null }
|
||||
| '(' Expr ')' { $2 }
|
||||
| '!' Expr { Unary Not $2 }
|
||||
| '-' Expr { Unary Negate $2 }
|
||||
|
||||
@@ -21,6 +21,7 @@ tokens :-
|
||||
return { \_ -> TokenReturn }
|
||||
new { \_ -> TokenNew }
|
||||
this { \_ -> TokenThis }
|
||||
null { \_ -> TokenNull }
|
||||
if { \_ -> TokenIf }
|
||||
else { \_ -> TokenElse }
|
||||
while { \_ -> TokenWhile }
|
||||
@@ -64,6 +65,7 @@ data Token
|
||||
| TokenReturn
|
||||
| TokenNew
|
||||
| TokenThis
|
||||
| TokenNull
|
||||
| TokenIf
|
||||
| TokenElse
|
||||
| TokenWhile
|
||||
|
||||
@@ -34,4 +34,5 @@ data TypedStmt
|
||||
| LocalVarDecl Type String Type
|
||||
| If TypedExpr TypedStmt (Maybe TypedStmt) Type
|
||||
| StmtExprStmt TypedStmtExpr Type
|
||||
| EmptyStmt Type
|
||||
deriving (Show, Eq)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module Main where
|
||||
|
||||
import Codegen.ClassFile (ClassFile, generateClassFile)
|
||||
import Codegen.Serializer (serializeClassFile)
|
||||
import qualified Data.ByteString as BS
|
||||
import Grammar.AST (Program)
|
||||
import Grammar.Parser (parse)
|
||||
import Grammar.Scanner (Token, alexScanTokens)
|
||||
@@ -22,8 +24,15 @@ runPipeline path = do
|
||||
let ast = parseProgram tokens
|
||||
let typedClasses = typeCheckProgram ast
|
||||
let classFiles = map generateClassFile typedClasses
|
||||
mapM_ writeClassFile (zip typedClasses classFiles)
|
||||
reportSuccess ast typedClasses classFiles
|
||||
|
||||
writeClassFile :: (TypedClass, ClassFile) -> IO ()
|
||||
writeClassFile (tc, cf) = do
|
||||
let outPath = "out/" ++ className tc ++ ".class"
|
||||
BS.writeFile outPath (BS.pack (serializeClassFile cf))
|
||||
putStrLn ("Written: " ++ outPath)
|
||||
|
||||
scan :: String -> [Token]
|
||||
scan = alexScanTokens
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
module Testsuite.AbcFiles.AllSyntaxTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 10, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 11, instruction = PutField 3},
|
||||
BtcLine {lineNumber = 14, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 15, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 16, instruction = GetField 3},
|
||||
BtcLine {lineNumber = 19, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 20, instruction = IAdd},
|
||||
BtcLine {lineNumber = 21, instruction = PutField 3},
|
||||
BtcLine {lineNumber = 24, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "inc",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 2, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 5, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 6, instruction = IAdd},
|
||||
BtcLine {lineNumber = 7, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 10, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 11, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 14, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "inc",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 2, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = IAdd},
|
||||
BtcLine {lineNumber = 7, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 10, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 11, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 14, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "sumUpTo",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 2, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 3, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = IfGt 20},
|
||||
BtcLine {lineNumber = 9, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 10, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 11, instruction = IAdd},
|
||||
BtcLine {lineNumber = 12, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 13, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 14, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 15, instruction = IAdd},
|
||||
BtcLine {lineNumber = 16, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 17, instruction = Goto 4},
|
||||
BtcLine {lineNumber = 20, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 21, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "predicate",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = BIPush 97},
|
||||
BtcLine {lineNumber = 2, instruction = IfEq 10},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = BIPush 98},
|
||||
BtcLine {lineNumber = 7, instruction = IfEq 10},
|
||||
BtcLine {lineNumber = 10, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 11, instruction = IReturn},
|
||||
BtcLine {lineNumber = 12, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 13, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
module Testsuite.AbcFiles.ArithmeticTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "basic",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 1, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 2, instruction = IAdd},
|
||||
BtcLine {lineNumber = 3, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 5, instruction = IMul},
|
||||
BtcLine {lineNumber = 6, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 7, instruction = ISub},
|
||||
BtcLine {lineNumber = 8, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 9, instruction = ISub},
|
||||
BtcLine {lineNumber = 10, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "logic",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 1, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 2, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 3, instruction = IAdd},
|
||||
BtcLine {lineNumber = 4, instruction = IAdd},
|
||||
BtcLine {lineNumber = 5, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,53 @@
|
||||
module Testsuite.AbcFiles.CombinedControlTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "compute",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 2, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 3, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 5, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 6, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 9, instruction = IfGe 37},
|
||||
BtcLine {lineNumber = 12, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 13, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 14, instruction = IDiv},
|
||||
BtcLine {lineNumber = 15, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 16, instruction = IMul},
|
||||
BtcLine {lineNumber = 17, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 18, instruction = ISub},
|
||||
BtcLine {lineNumber = 19, instruction = IfNe 31},
|
||||
BtcLine {lineNumber = 22, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 23, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 24, instruction = IAdd},
|
||||
BtcLine {lineNumber = 25, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 26, instruction = Goto 35},
|
||||
BtcLine {lineNumber = 29, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 30, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 31, instruction = ISub},
|
||||
BtcLine {lineNumber = 32, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 35, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 36, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 37, instruction = IAdd},
|
||||
BtcLine {lineNumber = 38, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 39, instruction = Goto 4},
|
||||
BtcLine {lineNumber = 42, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 43, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
module Testsuite.AbcFiles.ConstructorOverloadTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = Return}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
module Testsuite.AbcFiles.ConstructorTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = Return}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
module Testsuite.AbcFiles.EmptyTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
module Testsuite.AbcFiles.ExpressionTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "shortCircuit",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 2, instruction = IfEq 15},
|
||||
BtcLine {lineNumber = 5, instruction = BIPush 10},
|
||||
BtcLine {lineNumber = 6, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 7, instruction = IDiv},
|
||||
BtcLine {lineNumber = 8, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 9, instruction = IfLe 15},
|
||||
BtcLine {lineNumber = 12, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 13, instruction = Goto 16},
|
||||
BtcLine {lineNumber = 15, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 16, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 17, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 18, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "charArithmetic",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 2, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 3, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
module Testsuite.AbcFiles.FieldsTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = BIPush 42},
|
||||
BtcLine {lineNumber = 7, instruction = PutField 15},
|
||||
BtcLine {lineNumber = 10, instruction = Return}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
module Testsuite.AbcFiles.IfTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "ifElseTest",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 1, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 2, instruction = ISub},
|
||||
BtcLine {lineNumber = 3, instruction = IfGe 8},
|
||||
|
||||
BtcLine {lineNumber = 6, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 7, instruction = IReturn},
|
||||
|
||||
BtcLine {lineNumber = 8, instruction = Goto 27},
|
||||
|
||||
BtcLine {lineNumber = 11, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 12, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 13, instruction = ISub},
|
||||
BtcLine {lineNumber = 14, instruction = IfNe 8},
|
||||
|
||||
BtcLine {lineNumber = 17, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 18, instruction = IReturn},
|
||||
|
||||
BtcLine {lineNumber = 19, instruction = Goto 16},
|
||||
|
||||
BtcLine {lineNumber = 22, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 23, instruction = BIPush 10},
|
||||
BtcLine {lineNumber = 25, instruction = ISub},
|
||||
BtcLine {lineNumber = 26, instruction = IfGt 7},
|
||||
|
||||
BtcLine {lineNumber = 29, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 30, instruction = Goto 4},
|
||||
|
||||
BtcLine {lineNumber = 33, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 34, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
module Testsuite.AbcFiles.LoopTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "factorial",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 2, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 3, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = IfGt 21},
|
||||
BtcLine {lineNumber = 9, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 10, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 11, instruction = IMul},
|
||||
BtcLine {lineNumber = 12, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 13, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 14, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 15, instruction = IAdd},
|
||||
BtcLine {lineNumber = 16, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 17, instruction = Goto 4},
|
||||
BtcLine {lineNumber = 20, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 21, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "weirdFor",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 2, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 3, instruction = IConst 5},
|
||||
BtcLine {lineNumber = 4, instruction = IfGe 15},
|
||||
BtcLine {lineNumber = 7, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 8, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 9, instruction = IAdd},
|
||||
BtcLine {lineNumber = 10, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 11, instruction = Goto 2},
|
||||
BtcLine {lineNumber = 14, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 15, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,66 @@
|
||||
module Testsuite.AbcFiles.MaliciousTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "assignNegativeIncrement",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 2, instruction = IAdd},
|
||||
BtcLine {lineNumber = 3, instruction = ISub}, -- Using subtraction patterns for Unary Negative emulation
|
||||
BtcLine {lineNumber = 4, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 5, instruction = IAdd},
|
||||
BtcLine {lineNumber = 6, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 7, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 8, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "tripleAddition",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 2, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 3, instruction = IAdd},
|
||||
BtcLine {lineNumber = 4, instruction = IAdd},
|
||||
BtcLine {lineNumber = 5, instruction = IStore 4},
|
||||
BtcLine {lineNumber = 6, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 7, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 8, instruction = IAdd},
|
||||
BtcLine {lineNumber = 9, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 10, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 11, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 12, instruction = IAdd},
|
||||
BtcLine {lineNumber = 13, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 14, instruction = ILoad 3},
|
||||
BtcLine {lineNumber = 15, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 16, instruction = IAdd},
|
||||
BtcLine {lineNumber = 17, instruction = IStore 3},
|
||||
BtcLine {lineNumber = 18, instruction = ILoad 4},
|
||||
BtcLine {lineNumber = 19, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "cursedFormatting",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IfNe 7},
|
||||
BtcLine {lineNumber = 4, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 5, instruction = IReturn},
|
||||
BtcLine {lineNumber = 7, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 8, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 9, instruction = IfNe 15},
|
||||
BtcLine {lineNumber = 12, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 13, instruction = IReturn},
|
||||
BtcLine {lineNumber = 15, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 16, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
module Testsuite.AbcFiles.MethodOverloadTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "MethodOverload",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = BIPush 42},
|
||||
BtcLine {lineNumber = 1, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "MethodOverload",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = BIPush 42},
|
||||
BtcLine {lineNumber = 1, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 2, instruction = IAdd},
|
||||
BtcLine {lineNumber = 3, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
module Testsuite.AbcFiles.MultiClassTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "doubleIt",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = GetField 3},
|
||||
BtcLine {lineNumber = 4, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 5, instruction = IMul},
|
||||
BtcLine {lineNumber = 6, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
module Testsuite.AbcFiles.MultipleClassesTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = InvokeSpecial 2},
|
||||
BtcLine {lineNumber = 8, instruction = PutField 3},
|
||||
BtcLine {lineNumber = 11, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = BIPush 42},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 4},
|
||||
BtcLine {lineNumber = 9, instruction = Return}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,78 @@
|
||||
module Testsuite.AbcFiles.RecursionTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 9, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 10, instruction = IfLe 26},
|
||||
BtcLine {lineNumber = 13, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 14, instruction = Ldc 3},
|
||||
BtcLine {lineNumber = 16, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 17, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 18, instruction = ISub},
|
||||
BtcLine {lineNumber = 19, instruction = InvokeSpecial 4},
|
||||
BtcLine {lineNumber = 22, instruction = PutField 5},
|
||||
BtcLine {lineNumber = 25, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "fibonacci",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 2, instruction = IfGe 7},
|
||||
BtcLine {lineNumber = 5, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 6, instruction = IReturn},
|
||||
BtcLine {lineNumber = 7, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 8, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 9, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 10, instruction = ISub},
|
||||
BtcLine {lineNumber = 11, instruction = InvokeVirtual 6},
|
||||
BtcLine {lineNumber = 14, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 15, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 16, instruction = IConst 2},
|
||||
BtcLine {lineNumber = 17, instruction = ISub},
|
||||
BtcLine {lineNumber = 18, instruction = InvokeVirtual 6},
|
||||
BtcLine {lineNumber = 21, instruction = IAdd},
|
||||
BtcLine {lineNumber = 22, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "ackermann",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 1, instruction = IfNe 8},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 5, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 6, instruction = IAdd},
|
||||
BtcLine {lineNumber = 7, instruction = IReturn},
|
||||
BtcLine {lineNumber = 8, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 9, instruction = IfNe 21},
|
||||
BtcLine {lineNumber = 12, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 13, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 14, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 15, instruction = ISub},
|
||||
BtcLine {lineNumber = 16, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 17, instruction = InvokeVirtual 7},
|
||||
BtcLine {lineNumber = 20, instruction = IReturn},
|
||||
BtcLine {lineNumber = 21, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 22, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 23, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 24, instruction = ISub},
|
||||
BtcLine {lineNumber = 25, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 26, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 27, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 28, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 29, instruction = ISub},
|
||||
BtcLine {lineNumber = 30, instruction = InvokeVirtual 7},
|
||||
BtcLine {lineNumber = 33, instruction = InvokeVirtual 7},
|
||||
BtcLine {lineNumber = 36, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
module Testsuite.AbcFiles.ReturnTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "main",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = BIPush 42},
|
||||
BtcLine {lineNumber = 2, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
module Testsuite.AbcFiles.ShenaniganceTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "testAssignment",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 2, instruction = IConst 5},
|
||||
BtcLine {lineNumber = 3, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 4, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 5, instruction = IStore 2},
|
||||
BtcLine {lineNumber = 6, instruction = ILoad 2},
|
||||
BtcLine {lineNumber = 7, instruction = IReturn}
|
||||
]
|
||||
),
|
||||
( "divEqual",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = Ldc 2},
|
||||
BtcLine {lineNumber = 2, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 3, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 4, instruction = IConst 4},
|
||||
BtcLine {lineNumber = 5, instruction = IDiv},
|
||||
BtcLine {lineNumber = 6, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 7, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 8, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
module Testsuite.AbcFiles.SingletonTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[ ( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "getInstance",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 4, instruction = IfNe 17},
|
||||
BtcLine {lineNumber = 7, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 8, instruction = Ldc 3},
|
||||
BtcLine {lineNumber = 10, instruction = InvokeSpecial 1},
|
||||
BtcLine {lineNumber = 13, instruction = PutField 2},
|
||||
BtcLine {lineNumber = 17, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 18, instruction = GetField 2},
|
||||
BtcLine {lineNumber = 21, instruction = AReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
module Testsuite.AbcFiles.WhileTestABC (expectedABC) where
|
||||
|
||||
import Codegen.Lowerer (BtcLine (..), BtcProgram (..), Instruction (..))
|
||||
|
||||
expectedABC :: [(String, BtcProgram)]
|
||||
expectedABC =
|
||||
[
|
||||
( "<init>",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = ALoad0},
|
||||
BtcLine {lineNumber = 1, instruction = InvokeSpecial 8},
|
||||
BtcLine {lineNumber = 4, instruction = Return}
|
||||
]
|
||||
),
|
||||
( "whileLoopTest",
|
||||
BtcProgram
|
||||
[ BtcLine {lineNumber = 0, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 1, instruction = IStore 1},
|
||||
BtcLine {lineNumber = 2, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 3, instruction = IConst 0},
|
||||
BtcLine {lineNumber = 4, instruction = ISub},
|
||||
BtcLine {lineNumber = 5, instruction = IfLe 14},
|
||||
|
||||
BtcLine {lineNumber = 8, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 9, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 10, instruction = IAdd},
|
||||
BtcLine {lineNumber = 11, instruction = IStore 1},
|
||||
|
||||
BtcLine {lineNumber = 12, instruction = ILoad 0},
|
||||
BtcLine {lineNumber = 13, instruction = IConst 1},
|
||||
BtcLine {lineNumber = 14, instruction = ISub},
|
||||
BtcLine {lineNumber = 15, instruction = IStore 0},
|
||||
|
||||
BtcLine {lineNumber = 16, instruction = Goto 65522},
|
||||
|
||||
BtcLine {lineNumber = 19, instruction = ILoad 1},
|
||||
BtcLine {lineNumber = 20, instruction = IReturn}
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,76 @@
|
||||
module Testsuite.AstFiles.AllSyntaxTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"AllSyntaxTest"
|
||||
[ Field "int" "x" Nothing
|
||||
, Field "int" "counter" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "initial")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x") (LocalOrFieldVar "initial"))
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "counter") (Integer 0))
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "counter") (Binary Add (LocalOrFieldVar "counter") (Integer 1)))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"inc"
|
||||
[]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x") (Binary Add (LocalOrFieldVar "x") (Integer 1)))
|
||||
, Return (Just (LocalOrFieldVar "x"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"inc"
|
||||
[("int", "delta")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x") (Binary Add (LocalOrFieldVar "x") (LocalOrFieldVar "delta")))
|
||||
, Return (Just (LocalOrFieldVar "x"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"sumUpTo"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "s" (Just (Integer 0))
|
||||
, Block
|
||||
[ LocalVarDecl "int" "i" (Just (Integer 1))
|
||||
, While
|
||||
(Binary CompLessOrEqual (LocalOrFieldVar "i") (LocalOrFieldVar "n"))
|
||||
( Block
|
||||
[ Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "s") (Binary Add (LocalOrFieldVar "s") (LocalOrFieldVar "i")))
|
||||
]
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "i") (Binary Add (LocalOrFieldVar "i") (Integer 1)))
|
||||
]
|
||||
)
|
||||
]
|
||||
, Return (Just (LocalOrFieldVar "s"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"boolean"
|
||||
"predicate"
|
||||
[("char", "c")]
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
Or
|
||||
(Binary CompEqual (LocalOrFieldVar "c") (Char 'a'))
|
||||
(Binary CompEqual (LocalOrFieldVar "c") (Char 'b'))
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
module Testsuite.AstFiles.CombinedControlTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"CombinedControlTest"
|
||||
[ Field "int" "field" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "v")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "field") (LocalOrFieldVar "v"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"compute"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "i" (Just (Integer 0))
|
||||
, LocalVarDecl "int" "acc" (Just (Integer 0))
|
||||
, While
|
||||
(Binary CompLessThan (LocalOrFieldVar "i") (LocalOrFieldVar "field"))
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (Binary Modulo (LocalOrFieldVar "i") (Integer 2)) (Integer 0))
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "acc") (Binary Add (LocalOrFieldVar "acc") (LocalOrFieldVar "i")))])
|
||||
(Just (Block [StmtExprStmt (Assign (LocalOrFieldVar "acc") (Binary Subtract (LocalOrFieldVar "acc") (LocalOrFieldVar "i")))]))
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "i") (Binary Add (LocalOrFieldVar "i") (Integer 1)))
|
||||
]
|
||||
)
|
||||
, Return (Just (LocalOrFieldVar "acc"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
module Testsuite.AstFiles.ConstructorOverloadTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"ConstructorOverloadTest"
|
||||
[Field "int" "a" (Just (Integer 42))]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[]
|
||||
(Block []),
|
||||
Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "a")]
|
||||
(Block [StmtExprStmt (Assign (InstVar This "a") (LocalOrFieldVar "a"))])
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
module Testsuite.AstFiles.ConstructorTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"ConstructorTest"
|
||||
[Field "int" "a" (Just (Unary Negate (Integer 1)))]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "initial_value")]
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "a") (LocalOrFieldVar "initial_value"))])
|
||||
]
|
||||
]
|
||||
@@ -1,3 +0,0 @@
|
||||
[
|
||||
Class "EmptyTest" [] []
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
module Testsuite.AstFiles.EmptyTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"EmptyTest"
|
||||
[]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
module Testsuite.AstFiles.ExpressionTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"ExpressionTest"
|
||||
[]
|
||||
[ Method
|
||||
"boolean"
|
||||
"shortCircuit"
|
||||
[("int", "a"), ("int", "b")]
|
||||
( Block
|
||||
[ LocalVarDecl "boolean" "res" (Just (Binary And (Binary CompNotEqual (LocalOrFieldVar "a") (Integer 0)) (Binary CompGreaterThan (Binary Divide (Integer 10) (LocalOrFieldVar "a")) (LocalOrFieldVar "b"))))
|
||||
, Return (Just (LocalOrFieldVar "res"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"char"
|
||||
"charArithmetic"
|
||||
[("char", "c"), ("int", "offset")]
|
||||
( Block
|
||||
[ LocalVarDecl "char" "d" (Just (LocalOrFieldVar "c"))
|
||||
, Return (Just (LocalOrFieldVar "d"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,12 @@
|
||||
module Testsuite.AstFiles.FieldsTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"FieldsTest"
|
||||
[ Field "int" "a" Nothing,
|
||||
Field "int" "b" (Just (Integer 42))
|
||||
]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
module Testsuite.AstFiles.IfTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"IfTest"
|
||||
[]
|
||||
[ Method
|
||||
"boolean"
|
||||
"ifElseTest"
|
||||
[("int", "x")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompLessThan (LocalOrFieldVar "x") (Integer 0))
|
||||
(Block [Return (Just (Bool False))])
|
||||
( Just
|
||||
( If
|
||||
(Binary CompEqual (LocalOrFieldVar "x") (Integer 0))
|
||||
(Block [Return (Just (Bool True))])
|
||||
(Just (Block [Return (Just (Binary CompGreaterThan (LocalOrFieldVar "x") (Integer 10)))]))
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,50 @@
|
||||
module Testsuite.AstFiles.LoopTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"LoopTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"factorial"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "tally" (Just (Integer 1))
|
||||
, Block
|
||||
[ LocalVarDecl "int" "i" (Just (Integer 1))
|
||||
, While
|
||||
(Binary CompLessOrEqual (LocalOrFieldVar "i") (LocalOrFieldVar "n"))
|
||||
( Block
|
||||
[ Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "tally") (Binary Multiply (LocalOrFieldVar "tally") (LocalOrFieldVar "i")))
|
||||
]
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "i") (Binary Add (LocalOrFieldVar "i") (Integer 1)))
|
||||
]
|
||||
)
|
||||
]
|
||||
, Return (Just (LocalOrFieldVar "tally"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"weirdFor"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "k" (Just (Integer 0))
|
||||
, Block
|
||||
[ EmptyStmt
|
||||
, While
|
||||
(Binary CompLessThan (LocalOrFieldVar "k") (Integer 5))
|
||||
( Block
|
||||
[ Block []
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "k") (Binary Add (LocalOrFieldVar "k") (Integer 1)))
|
||||
]
|
||||
)
|
||||
]
|
||||
, Return (Just (LocalOrFieldVar "k"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
module Testsuite.AstFiles.MaliciousTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"MaliciousTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"cursedFormatting"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "n") (Integer 0))
|
||||
(Block [Return (Just (Integer 0))])
|
||||
( Just
|
||||
( If
|
||||
(Binary CompEqual (LocalOrFieldVar "n") (Integer 1))
|
||||
(Block [Return (Just (Integer 1))])
|
||||
(Just (Block [Return (Just (Integer 2))]))
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
module Testsuite.AstFiles.MethodOverloadTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"MethodOverloadTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"MethodOverload"
|
||||
[]
|
||||
(Block [Return (Just (Integer 42))]),
|
||||
Method
|
||||
"int"
|
||||
"MethodOverload"
|
||||
[("int", "a")]
|
||||
(Block [Return (Just (Binary Add (Integer 42) (LocalOrFieldVar "a")))])
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
module Testsuite.AstFiles.MultiClassTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"MultiClassTest"
|
||||
[]
|
||||
[],
|
||||
Class
|
||||
"Helper"
|
||||
[Field "int" "v" Nothing]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "v0")]
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "v") (LocalOrFieldVar "v0"))]),
|
||||
Method
|
||||
"int"
|
||||
"doubleIt"
|
||||
[]
|
||||
(Block [Return (Just (Binary Multiply (LocalOrFieldVar "v") (Integer 2)))])
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,16 @@
|
||||
module Testsuite.AstFiles.MultipleClassesTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"MultipleClassesTest"
|
||||
[ Field "AnotherTestClass" "a" (Just (StmtExprExpr (New "AnotherTestClass" [])))
|
||||
]
|
||||
[]
|
||||
, Class
|
||||
"AnotherTestClass"
|
||||
[ Field "int" "a" (Just (Integer 42))
|
||||
]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,77 @@
|
||||
module Testsuite.AstFiles.RecursionTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"RecursionTest"
|
||||
[ Field "int" "value" (Just (Integer 0))
|
||||
, Field "RecursionTest" "child" (Just Null)
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (InstVar This "value") (LocalOrFieldVar "n"))
|
||||
, If
|
||||
(Binary CompGreaterThan (LocalOrFieldVar "n") (Integer 0))
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "child") (StmtExprExpr (New "RecursionTest" [Binary Subtract (LocalOrFieldVar "n") (Integer 1)])))
|
||||
]
|
||||
)
|
||||
Nothing
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"fibonacci"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompLessThan (LocalOrFieldVar "n") (Integer 2))
|
||||
(Block [Return (Just (LocalOrFieldVar "n"))])
|
||||
( Just
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
Add
|
||||
(StmtExprExpr (MethodCall This "fibonacci" [Binary Subtract (LocalOrFieldVar "n") (Integer 1)]))
|
||||
(StmtExprExpr (MethodCall This "fibonacci" [Binary Subtract (LocalOrFieldVar "n") (Integer 2)]))
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"ackermann"
|
||||
[("int", "m"), ("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "m") (Integer 0))
|
||||
(Return (Just (Binary Add (LocalOrFieldVar "n") (Integer 1))))
|
||||
Nothing
|
||||
, If
|
||||
(Binary CompEqual (LocalOrFieldVar "n") (Integer 0))
|
||||
(Return (Just (StmtExprExpr (MethodCall This "ackermann" [Binary Subtract (LocalOrFieldVar "m") (Integer 1), Integer 1]))))
|
||||
Nothing
|
||||
, Return
|
||||
( Just
|
||||
( StmtExprExpr
|
||||
( MethodCall
|
||||
This
|
||||
"ackermann"
|
||||
[ Binary Subtract (LocalOrFieldVar "m") (Integer 1)
|
||||
, StmtExprExpr (MethodCall This "ackermann" [LocalOrFieldVar "m", Binary Subtract (LocalOrFieldVar "n") (Integer 1)])
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
module Testsuite.AstFiles.ReturnTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"ReturnTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"main"
|
||||
[]
|
||||
( Block [Return (Just (Integer 42))] )
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
module Testsuite.AstFiles.ShenaniganceTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"ShenaniganceTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"testAssignment"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "x" (Just (Integer 1))
|
||||
, LocalVarDecl "int" "y" (Just (StmtExprExpr (Assign (LocalOrFieldVar "x") (Integer 5))))
|
||||
, Return (Just (LocalOrFieldVar "y"))
|
||||
]
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"divEqual"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "x" (Just (Integer 234343000))
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "x") (Binary Divide (LocalOrFieldVar "x") (Integer 4)))
|
||||
, Return (Just (LocalOrFieldVar "x"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
module Testsuite.AstFiles.SingletonTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"SingletonTest"
|
||||
[ Field "SingletonTest" "instance" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[]
|
||||
(Block [])
|
||||
, Method
|
||||
"SingletonTest"
|
||||
"getInstance"
|
||||
[]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "instance") Null)
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "instance") (StmtExprExpr (New "SingletonTest" [])))])
|
||||
Nothing
|
||||
, Return (Just (LocalOrFieldVar "instance"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
module Testsuite.AstFiles.WhileTestAST (expectedAST) where
|
||||
|
||||
import Grammar.AST
|
||||
|
||||
expectedAST =
|
||||
[ Class
|
||||
"WhileTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"whileLoopTest"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "sum" (Just (Integer 0)),
|
||||
While
|
||||
(Binary CompGreaterThan (LocalOrFieldVar "n") (Integer 0))
|
||||
( Block
|
||||
[ StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "sum")
|
||||
(Binary Add (LocalOrFieldVar "sum") (LocalOrFieldVar "n"))
|
||||
),
|
||||
StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "n")
|
||||
(Binary Subtract (LocalOrFieldVar "n") (Integer 1))
|
||||
)
|
||||
]
|
||||
),
|
||||
Return (Just (LocalOrFieldVar "sum"))
|
||||
]
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -1,95 +0,0 @@
|
||||
module Main where
|
||||
|
||||
import Codegen.Assemble (assembleProgram)
|
||||
import Codegen.ClassFile (ClassFile(..), ClassFileMethod(..))
|
||||
import Codegen.Errors (CodegenError(..))
|
||||
import Codegen.IR
|
||||
( ClassDef(..)
|
||||
, Expr(..)
|
||||
, Literal(..)
|
||||
, MethodDef(..)
|
||||
, Program(..)
|
||||
, Stmt(..)
|
||||
, Type(..)
|
||||
)
|
||||
import Data.List (isInfixOf)
|
||||
import System.Exit (exitFailure)
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
testVerticalSliceReturnInt
|
||||
testUnsupportedStatementFails
|
||||
putStrLn "Codegen smoke tests passed."
|
||||
|
||||
testVerticalSliceReturnInt :: IO ()
|
||||
testVerticalSliceReturnInt =
|
||||
case assembleProgram program of
|
||||
Left err -> failTest ("Expected successful assemble, got error: " ++ show err)
|
||||
Right [classFile] -> do
|
||||
assertEqual "class name" "Main" (cfClassName classFile)
|
||||
case cfMethods classFile of
|
||||
[method] -> do
|
||||
assertEqual "method name" "constSeven" (cfmName method)
|
||||
assertEqual "method descriptor" "()I" (cfmDescriptor method)
|
||||
assertEqual "method instructions" ["iconst 7", "ireturn"] (cfmCode method)
|
||||
_ -> failTest "Expected exactly one method in generated class"
|
||||
Right _ -> failTest "Expected exactly one generated class"
|
||||
where
|
||||
program =
|
||||
Program
|
||||
[ ClassDef
|
||||
{ className = "Main"
|
||||
, classFields = []
|
||||
, classMethods =
|
||||
[ MethodDef
|
||||
{ methodName = "constSeven"
|
||||
, methodParams = []
|
||||
, methodReturnType = IntType
|
||||
, methodBody = Return (Literal (IntLit 7))
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
testUnsupportedStatementFails :: IO ()
|
||||
testUnsupportedStatementFails =
|
||||
case assembleProgram program of
|
||||
Left (LoweringError msg)
|
||||
| "Unsupported statement" `isInfixOf` msg -> pure ()
|
||||
| otherwise -> failTest ("Lowering failed with unexpected message: " ++ msg)
|
||||
Left err -> failTest ("Expected LoweringError, got: " ++ show err)
|
||||
Right _ -> failTest "Expected lowering to fail for unsupported statement"
|
||||
where
|
||||
program =
|
||||
Program
|
||||
[ ClassDef
|
||||
{ className = "Main"
|
||||
, classFields = []
|
||||
, classMethods =
|
||||
[ MethodDef
|
||||
{ methodName = "badMethod"
|
||||
, methodParams = []
|
||||
, methodReturnType = IntType
|
||||
, methodBody = While (Literal (BoolLit True)) (Return (Literal (IntLit 0)))
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
assertEqual :: (Eq a, Show a) => String -> a -> a -> IO ()
|
||||
assertEqual label expected actual
|
||||
| expected == actual = pure ()
|
||||
| otherwise =
|
||||
failTest
|
||||
( "Assertion failed for "
|
||||
++ label
|
||||
++ ": expected "
|
||||
++ show expected
|
||||
++ ", got "
|
||||
++ show actual
|
||||
)
|
||||
|
||||
failTest :: String -> IO ()
|
||||
failTest message = do
|
||||
putStrLn ("[FAIL] " ++ message)
|
||||
exitFailure
|
||||
@@ -1,14 +0,0 @@
|
||||
module TestSuite.ExecutableTests.ArithmeticASTTest where
|
||||
|
||||
import Grammar.Parser
|
||||
import Grammar.Scanner
|
||||
import Testsuite.AstFiles.ArithmeticTestAST (expectedAST)
|
||||
|
||||
mainArithemticASTTest :: IO ()
|
||||
mainArithemticASTTest = do
|
||||
let javaFilePath = "Testsuite/javaFiles/ArithmeticTest.java"
|
||||
java <- readFile javaFilePath
|
||||
let actualAST = parse . alexScanTokens $ java
|
||||
print $ actualAST == expectedAST
|
||||
print actualAST
|
||||
print expectedAST
|
||||
@@ -0,0 +1,114 @@
|
||||
module Testsuite.ExecutableTests.HarnessSupport
|
||||
( TestResult (..),
|
||||
TestFailure (..),
|
||||
runNamedTests,
|
||||
printTestResults,
|
||||
exitOnFailures
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Exception (Exception, SomeException, fromException, try)
|
||||
import Data.List (dropWhileEnd, intercalate)
|
||||
import System.Exit (ExitCode (..), exitFailure)
|
||||
import System.IO (BufferMode (LineBuffering), hFlush, hSetBuffering, stderr, stdout)
|
||||
|
||||
newtype TestFailure = TestFailure {failureDetails :: String}
|
||||
deriving (Show)
|
||||
|
||||
instance Exception TestFailure
|
||||
|
||||
data TestResult = TestResult
|
||||
{ testName :: String,
|
||||
passed :: Bool,
|
||||
details :: String
|
||||
}
|
||||
deriving (Eq, Show)
|
||||
|
||||
runNamedTests :: [(String, IO ())] -> IO [TestResult]
|
||||
runNamedTests tests = do
|
||||
hSetBuffering stdout LineBuffering
|
||||
hSetBuffering stderr LineBuffering
|
||||
runNamedTests' tests
|
||||
|
||||
runNamedTests' :: [(String, IO ())] -> IO [TestResult]
|
||||
runNamedTests' [] = pure []
|
||||
runNamedTests' (test : rest) = do
|
||||
result <- runNamedTest test
|
||||
results <- runNamedTests' rest
|
||||
pure (result : results)
|
||||
|
||||
runNamedTest :: (String, IO ()) -> IO TestResult
|
||||
runNamedTest (name, action) = do
|
||||
putStrLn ("[RUN ] " ++ name)
|
||||
hFlush stdout
|
||||
result <- try action :: IO (Either SomeException ())
|
||||
case result of
|
||||
Right () -> do
|
||||
putStrLn ("[DONE] " ++ name)
|
||||
hFlush stdout
|
||||
pure (TestResult name True "")
|
||||
Left ex -> do
|
||||
let details = failureDetailsForSummary ex
|
||||
let runtimeDetails = failureDetailsForRuntime ex
|
||||
if null runtimeDetails
|
||||
then pure ()
|
||||
else putStrLn runtimeDetails
|
||||
putStrLn ("[DONE] " ++ name)
|
||||
hFlush stdout
|
||||
pure (TestResult name False details)
|
||||
|
||||
printTestResults :: String -> [TestResult] -> IO ()
|
||||
printTestResults title results = do
|
||||
putStrLn ("\n== " ++ title ++ " ==")
|
||||
mapM_ printResult results
|
||||
let total = length results
|
||||
failures = length (filter (not . passed) results)
|
||||
successes = total - failures
|
||||
putStrLn ("Summary: " ++ show successes ++ "/" ++ show total ++ " passed")
|
||||
|
||||
printResult :: TestResult -> IO ()
|
||||
printResult (TestResult name True _) =
|
||||
putStrLn ("[PASS] " ++ name)
|
||||
printResult (TestResult name False info) = do
|
||||
let ls = lines info
|
||||
firstLine = if null ls then "" else head ls
|
||||
rest = if null ls then [] else tail ls
|
||||
header = "[FAIL] " ++ name ++ (if null firstLine then "" else " - " ++ firstLine)
|
||||
putStrLn header
|
||||
if null rest
|
||||
then pure ()
|
||||
else mapM_ (putStrLn . (" " ++)) rest
|
||||
|
||||
exitOnFailures :: [TestResult] -> IO ()
|
||||
exitOnFailures results =
|
||||
if any (not . passed) results
|
||||
then exitFailure
|
||||
else pure ()
|
||||
|
||||
renderException :: SomeException -> String
|
||||
renderException ex =
|
||||
case fromException ex :: Maybe ExitCode of
|
||||
Just ExitSuccess -> "unexpected ExitSuccess exception"
|
||||
Just (ExitFailure code) -> "exit failure code " ++ show code
|
||||
Nothing -> sanitize (show ex)
|
||||
|
||||
failureDetailsForRuntime :: SomeException -> String
|
||||
failureDetailsForRuntime ex =
|
||||
case fromException ex :: Maybe TestFailure of
|
||||
Just (TestFailure details) -> stripTrailingNewlines details
|
||||
Nothing -> indentOneLine (renderException ex)
|
||||
|
||||
failureDetailsForSummary :: SomeException -> String
|
||||
failureDetailsForSummary ex =
|
||||
case fromException ex :: Maybe TestFailure of
|
||||
Just (TestFailure details) -> stripTrailingNewlines details
|
||||
Nothing -> renderException ex
|
||||
|
||||
indentOneLine :: String -> String
|
||||
indentOneLine text = " " ++ text
|
||||
|
||||
stripTrailingNewlines :: String -> String
|
||||
stripTrailingNewlines = dropWhileEnd (== '\n') . dropWhileEnd (== '\r')
|
||||
|
||||
sanitize :: String -> String
|
||||
sanitize = intercalate " " . words
|
||||
@@ -0,0 +1,79 @@
|
||||
module Testsuite.ExecutableTests.Main where
|
||||
|
||||
import System.Environment (getArgs)
|
||||
import System.Exit (exitFailure)
|
||||
import Control.Monad (forM)
|
||||
import Control.Exception (try, SomeException)
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
import Testsuite.ExecutableTests.Registry
|
||||
import Testsuite.ExecutableTests.Runner.AST
|
||||
import Testsuite.ExecutableTests.Runner.TAST
|
||||
import Testsuite.ExecutableTests.Runner.ABC
|
||||
import Testsuite.ExecutableTests.Runner.Bytecode
|
||||
import Testsuite.ExecutableTests.HarnessSupport (TestResult(..), printTestResults, exitOnFailures, runNamedTests)
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
args <- getArgs
|
||||
case args of
|
||||
[] -> runAll
|
||||
[testName] -> runSpecific testName
|
||||
_ -> do
|
||||
putStrLn "Usage: runghc -isrc src/Testsuite/ExecutableTests/Main.hs [testName]"
|
||||
putStrLn " No argument: run all tests"
|
||||
putStrLn " testName: run specific test (e.g., EmptyTest)"
|
||||
exitFailure
|
||||
|
||||
runAll :: IO ()
|
||||
runAll = do
|
||||
resultLists <- forM allTests $ \tc -> do
|
||||
putStrLn ""
|
||||
putStrLn ("=== " ++ tcName tc ++ " ===")
|
||||
eres <- try (runTest tc) :: IO (Either SomeException [TestResult])
|
||||
case eres of
|
||||
Right rs -> pure rs
|
||||
Left ex -> do
|
||||
let msg = unwords (words (show ex))
|
||||
putStrLn ("[ERROR] " ++ tcName tc ++ " - " ++ msg)
|
||||
pure [TestResult (tcName tc) False msg]
|
||||
let results = concat resultLists
|
||||
printTestResults "Full Testsuite" results
|
||||
-- Per-test summary
|
||||
putStrLn "\n=== Summary ==="
|
||||
let perTest = zip allTests resultLists
|
||||
mapM_ (\(tc, rs) -> do
|
||||
let total = length rs
|
||||
passedCount = length (filter passed rs)
|
||||
status = if passedCount == total then "PASS" else "FAIL"
|
||||
putStrLn ("[" ++ status ++ "] " ++ tcName tc ++ " - " ++ show passedCount ++ "/" ++ show total ++ " tests passed")
|
||||
) perTest
|
||||
exitOnFailures results
|
||||
|
||||
runSpecific :: String -> IO ()
|
||||
runSpecific testName =
|
||||
case findTestByName testName allTests of
|
||||
Nothing -> do
|
||||
putStrLn $ "Test not found: " ++ testName
|
||||
putStrLn "Available tests:"
|
||||
mapM_ (putStrLn . (" - " ++) . tcName) allTests
|
||||
exitFailure
|
||||
Just tc -> do
|
||||
results <- runTest tc
|
||||
printTestResults testName results
|
||||
exitOnFailures results
|
||||
|
||||
findTestByName :: String -> [TestCase] -> Maybe TestCase
|
||||
findTestByName _ [] = Nothing
|
||||
findTestByName name (tc:tcs)
|
||||
| tcName tc == name = Just tc
|
||||
| otherwise = findTestByName name tcs
|
||||
|
||||
runTest :: TestCase -> IO [TestResult]
|
||||
runTest tc =
|
||||
let prefix = tcName tc ++ " "
|
||||
in runNamedTests
|
||||
[ (prefix ++ "AST", runASTTest tc)
|
||||
, (prefix ++ "TAST", runTASTTest tc)
|
||||
, (prefix ++ "ABC", runABCTest tc)
|
||||
, (prefix ++ "Bytecode", runBytecodeTest tc)
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
module Testsuite.ExecutableTests.Registry where
|
||||
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
|
||||
-- AllSyntaxTest
|
||||
import qualified Testsuite.AstFiles.AllSyntaxTestAST as AllSyntaxAST
|
||||
import qualified Testsuite.TastFiles.AllSyntaxTestTAST as AllSyntaxTAST
|
||||
import qualified Testsuite.AbcFiles.AllSyntaxTestABC as AllSyntaxABC
|
||||
|
||||
-- ArithmeticTest
|
||||
import qualified Testsuite.AstFiles.ArithmeticTestAST as ArithmeticAST
|
||||
import qualified Testsuite.TastFiles.ArithmeticTestTAST as ArithmeticTAST
|
||||
import qualified Testsuite.AbcFiles.ArithmeticTestABC as ArithmeticABC
|
||||
|
||||
-- CombinedControlTest
|
||||
import qualified Testsuite.AstFiles.CombinedControlTestAST as CombinedControlAST
|
||||
import qualified Testsuite.TastFiles.CombinedControlTestTAST as CombinedControlTAST
|
||||
import qualified Testsuite.AbcFiles.CombinedControlTestABC as CombinedControlABC
|
||||
|
||||
-- ConstructorOverloadTest
|
||||
import qualified Testsuite.AstFiles.ConstructorOverloadTestAST as ConstructorOverloadAST
|
||||
import qualified Testsuite.TastFiles.ConstructorOverloadTestTAST as ConstructorOverloadTAST
|
||||
import qualified Testsuite.AbcFiles.ConstructorOverloadTestABC as ConstructorOverloadABC
|
||||
|
||||
-- ConstructorTest
|
||||
import qualified Testsuite.AstFiles.ConstructorTestAST as ConstructorAST
|
||||
import qualified Testsuite.TastFiles.ConstructorTestTAST as ConstructorTAST
|
||||
import qualified Testsuite.AbcFiles.ConstructorTestABC as ConstructorABC
|
||||
|
||||
-- EmptyTest
|
||||
import qualified Testsuite.AstFiles.EmptyTestAST as EmptyAST
|
||||
import qualified Testsuite.TastFiles.EmptyTestTAST as EmptyTAST
|
||||
import qualified Testsuite.AbcFiles.EmptyTestABC as EmptyABC
|
||||
|
||||
-- ExpressionTest
|
||||
import qualified Testsuite.AstFiles.ExpressionTestAST as ExpressionAST
|
||||
import qualified Testsuite.TastFiles.ExpressionTestTAST as ExpressionTAST
|
||||
import qualified Testsuite.AbcFiles.ExpressionTestABC as ExpressionABC
|
||||
|
||||
-- FieldsTest
|
||||
import qualified Testsuite.AstFiles.FieldsTestAST as FieldsAST
|
||||
import qualified Testsuite.TastFiles.FieldsTestTAST as FieldsTAST
|
||||
import qualified Testsuite.AbcFiles.FieldsTestABC as FieldsABC
|
||||
|
||||
-- IfTest
|
||||
import qualified Testsuite.AstFiles.IfTestAST as IfAST
|
||||
import qualified Testsuite.TastFiles.IfTestTAST as IfTAST
|
||||
import qualified Testsuite.AbcFiles.IfTestABC as IfABC
|
||||
|
||||
-- LoopTest
|
||||
import qualified Testsuite.AstFiles.LoopTestAST as LoopAST
|
||||
import qualified Testsuite.TastFiles.LoopTestTAST as LoopTAST
|
||||
import qualified Testsuite.AbcFiles.LoopTestABC as LoopABC
|
||||
|
||||
-- MaliciousTest
|
||||
import qualified Testsuite.AstFiles.MaliciousTestAST as MaliciousAST
|
||||
import qualified Testsuite.TastFiles.MaliciousTestTAST as MaliciousTAST
|
||||
import qualified Testsuite.AbcFiles.MaliciousTestABC as MaliciousABC
|
||||
|
||||
-- MethodOverloadTest
|
||||
import qualified Testsuite.AstFiles.MethodOverloadTestAST as MethodOverloadAST
|
||||
import qualified Testsuite.TastFiles.MethodOverloadTestTAST as MethodOverloadTAST
|
||||
import qualified Testsuite.AbcFiles.MethodOverloadTestABC as MethodOverloadABC
|
||||
|
||||
-- MultiClassTest
|
||||
import qualified Testsuite.AstFiles.MultiClassTestAST as MultiClassAST
|
||||
import qualified Testsuite.TastFiles.MultiClassTestTAST as MultiClassTAST
|
||||
import qualified Testsuite.AbcFiles.MultiClassTestABC as MultiClassABC
|
||||
|
||||
-- MultipleClassesTest
|
||||
import qualified Testsuite.AstFiles.MultipleClassesTestAST as MultipleClassesAST
|
||||
import qualified Testsuite.TastFiles.MultipleClassesTestTAST as MultipleClassesTAST
|
||||
import qualified Testsuite.AbcFiles.MultipleClassesTestABC as MultipleClassesABC
|
||||
|
||||
-- RecursionTest
|
||||
import qualified Testsuite.AstFiles.RecursionTestAST as RecursionAST
|
||||
import qualified Testsuite.TastFiles.RecursionTestTAST as RecursionTAST
|
||||
import qualified Testsuite.AbcFiles.RecursionTestABC as RecursionABC
|
||||
|
||||
-- ReturnTest
|
||||
import qualified Testsuite.AstFiles.ReturnTestAST as ReturnAST
|
||||
import qualified Testsuite.TastFiles.ReturnTestTAST as ReturnTAST
|
||||
import qualified Testsuite.AbcFiles.ReturnTestABC as ReturnABC
|
||||
|
||||
-- ShenaniganceTest
|
||||
import qualified Testsuite.AstFiles.ShenaniganceTestAST as ShenaniganceAST
|
||||
import qualified Testsuite.TastFiles.ShenaniganceTestTAST as ShenaniganceTAST
|
||||
import qualified Testsuite.AbcFiles.ShenaniganceTestABC as ShenaniganceABC
|
||||
|
||||
-- SingletonTest
|
||||
import qualified Testsuite.AstFiles.SingletonTestAST as SingletonAST
|
||||
import qualified Testsuite.TastFiles.SingletonTestTAST as SingletonTAST
|
||||
import qualified Testsuite.AbcFiles.SingletonTestABC as SingletonABC
|
||||
|
||||
-- WhileTest
|
||||
import qualified Testsuite.AstFiles.WhileTestAST as WhileAST
|
||||
import qualified Testsuite.TastFiles.WhileTestTAST as WhileTAST
|
||||
import qualified Testsuite.AbcFiles.WhileTestABC as WhileABC
|
||||
|
||||
import Codegen.Serializer (serializeProgram)
|
||||
import Data.Word (Word8)
|
||||
import qualified Codegen.Lowerer
|
||||
|
||||
toBytecode :: [(String, Codegen.Lowerer.BtcProgram)] -> [(String, [Word8])]
|
||||
toBytecode = map (fmap (serializeProgram))
|
||||
|
||||
allTests :: [TestCase]
|
||||
allTests =
|
||||
[ allSyntaxTest
|
||||
, arithmeticTest
|
||||
, combinedControlTest
|
||||
, constructorOverloadTest
|
||||
, constructorTest
|
||||
, emptyTest
|
||||
, expressionTest
|
||||
, fieldsTest
|
||||
, ifTest
|
||||
, loopTest
|
||||
, maliciousTest
|
||||
, methodOverloadTest
|
||||
, multiClassTest
|
||||
, multipleClassesTest
|
||||
, recursionTest
|
||||
, returnTest
|
||||
, shenaniganceTest
|
||||
, singletonTest
|
||||
, whileTest
|
||||
]
|
||||
|
||||
allSyntaxTest :: TestCase
|
||||
allSyntaxTest =
|
||||
TestCase
|
||||
{ tcName = "AllSyntaxTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/AllSyntaxTest.java"
|
||||
, tcExpectedAST = AllSyntaxAST.expectedAST
|
||||
, tcExpectedTAST = AllSyntaxTAST.expectedTAST
|
||||
, tcExpectedABC = AllSyntaxABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode AllSyntaxABC.expectedABC
|
||||
}
|
||||
|
||||
arithmeticTest :: TestCase
|
||||
arithmeticTest =
|
||||
TestCase
|
||||
{ tcName = "ArithmeticTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ArithmeticTest.java"
|
||||
, tcExpectedAST = ArithmeticAST.expectedAST
|
||||
, tcExpectedTAST = ArithmeticTAST.expectedTAST
|
||||
, tcExpectedABC = ArithmeticABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ArithmeticABC.expectedABC
|
||||
}
|
||||
|
||||
combinedControlTest :: TestCase
|
||||
combinedControlTest =
|
||||
TestCase
|
||||
{ tcName = "CombinedControlTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/CombinedControlTest.java"
|
||||
, tcExpectedAST = CombinedControlAST.expectedAST
|
||||
, tcExpectedTAST = CombinedControlTAST.expectedTAST
|
||||
, tcExpectedABC = CombinedControlABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode CombinedControlABC.expectedABC
|
||||
}
|
||||
|
||||
constructorOverloadTest :: TestCase
|
||||
constructorOverloadTest =
|
||||
TestCase
|
||||
{ tcName = "ConstructorOverloadTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ConstructorOverloadTest.java"
|
||||
, tcExpectedAST = ConstructorOverloadAST.expectedAST
|
||||
, tcExpectedTAST = ConstructorOverloadTAST.expectedTAST
|
||||
, tcExpectedABC = ConstructorOverloadABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ConstructorOverloadABC.expectedABC
|
||||
}
|
||||
|
||||
constructorTest :: TestCase
|
||||
constructorTest =
|
||||
TestCase
|
||||
{ tcName = "ConstructorTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ConstructorTest.java"
|
||||
, tcExpectedAST = ConstructorAST.expectedAST
|
||||
, tcExpectedTAST = ConstructorTAST.expectedTAST
|
||||
, tcExpectedABC = ConstructorABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ConstructorABC.expectedABC
|
||||
}
|
||||
|
||||
emptyTest :: TestCase
|
||||
emptyTest =
|
||||
TestCase
|
||||
{ tcName = "EmptyTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/EmptyTest.java"
|
||||
, tcExpectedAST = EmptyAST.expectedAST
|
||||
, tcExpectedTAST = EmptyTAST.expectedTAST
|
||||
, tcExpectedABC = EmptyABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode EmptyABC.expectedABC
|
||||
}
|
||||
|
||||
expressionTest :: TestCase
|
||||
expressionTest =
|
||||
TestCase
|
||||
{ tcName = "ExpressionTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ExpressionTest.java"
|
||||
, tcExpectedAST = ExpressionAST.expectedAST
|
||||
, tcExpectedTAST = ExpressionTAST.expectedTAST
|
||||
, tcExpectedABC = ExpressionABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ExpressionABC.expectedABC
|
||||
}
|
||||
|
||||
fieldsTest :: TestCase
|
||||
fieldsTest =
|
||||
TestCase
|
||||
{ tcName = "FieldsTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/FieldsTest.java"
|
||||
, tcExpectedAST = FieldsAST.expectedAST
|
||||
, tcExpectedTAST = FieldsTAST.expectedTAST
|
||||
, tcExpectedABC = FieldsABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode FieldsABC.expectedABC
|
||||
}
|
||||
|
||||
ifTest :: TestCase
|
||||
ifTest =
|
||||
TestCase
|
||||
{ tcName = "IfTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/IfTest.java"
|
||||
, tcExpectedAST = IfAST.expectedAST
|
||||
, tcExpectedTAST = IfTAST.expectedTAST
|
||||
, tcExpectedABC = IfABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode IfABC.expectedABC
|
||||
}
|
||||
|
||||
loopTest :: TestCase
|
||||
loopTest =
|
||||
TestCase
|
||||
{ tcName = "LoopTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/LoopTest.java"
|
||||
, tcExpectedAST = LoopAST.expectedAST
|
||||
, tcExpectedTAST = LoopTAST.expectedTAST
|
||||
, tcExpectedABC = LoopABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode LoopABC.expectedABC
|
||||
}
|
||||
|
||||
maliciousTest :: TestCase
|
||||
maliciousTest =
|
||||
TestCase
|
||||
{ tcName = "MaliciousTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/MaliciousTest.java"
|
||||
, tcExpectedAST = MaliciousAST.expectedAST
|
||||
, tcExpectedTAST = MaliciousTAST.expectedTAST
|
||||
, tcExpectedABC = MaliciousABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode MaliciousABC.expectedABC
|
||||
}
|
||||
|
||||
methodOverloadTest :: TestCase
|
||||
methodOverloadTest =
|
||||
TestCase
|
||||
{ tcName = "MethodOverloadTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/MethodOverloadTest.java"
|
||||
, tcExpectedAST = MethodOverloadAST.expectedAST
|
||||
, tcExpectedTAST = MethodOverloadTAST.expectedTAST
|
||||
, tcExpectedABC = MethodOverloadABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode MethodOverloadABC.expectedABC
|
||||
}
|
||||
|
||||
multiClassTest :: TestCase
|
||||
multiClassTest =
|
||||
TestCase
|
||||
{ tcName = "MultiClassTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/MultiClassTest.java"
|
||||
, tcExpectedAST = MultiClassAST.expectedAST
|
||||
, tcExpectedTAST = MultiClassTAST.expectedTAST
|
||||
, tcExpectedABC = MultiClassABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode MultiClassABC.expectedABC
|
||||
}
|
||||
|
||||
multipleClassesTest :: TestCase
|
||||
multipleClassesTest =
|
||||
TestCase
|
||||
{ tcName = "MultipleClassesTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/MultipleClassesTest.java"
|
||||
, tcExpectedAST = MultipleClassesAST.expectedAST
|
||||
, tcExpectedTAST = MultipleClassesTAST.expectedTAST
|
||||
, tcExpectedABC = MultipleClassesABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode MultipleClassesABC.expectedABC
|
||||
}
|
||||
|
||||
recursionTest :: TestCase
|
||||
recursionTest =
|
||||
TestCase
|
||||
{ tcName = "RecursionTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/RecursionTest.java"
|
||||
, tcExpectedAST = RecursionAST.expectedAST
|
||||
, tcExpectedTAST = RecursionTAST.expectedTAST
|
||||
, tcExpectedABC = RecursionABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode RecursionABC.expectedABC
|
||||
}
|
||||
|
||||
returnTest :: TestCase
|
||||
returnTest =
|
||||
TestCase
|
||||
{ tcName = "ReturnTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ReturnTest.java"
|
||||
, tcExpectedAST = ReturnAST.expectedAST
|
||||
, tcExpectedTAST = ReturnTAST.expectedTAST
|
||||
, tcExpectedABC = ReturnABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ReturnABC.expectedABC
|
||||
}
|
||||
|
||||
shenaniganceTest :: TestCase
|
||||
shenaniganceTest =
|
||||
TestCase
|
||||
{ tcName = "ShenaniganceTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/ShenaniganceTest.java"
|
||||
, tcExpectedAST = ShenaniganceAST.expectedAST
|
||||
, tcExpectedTAST = ShenaniganceTAST.expectedTAST
|
||||
, tcExpectedABC = ShenaniganceABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode ShenaniganceABC.expectedABC
|
||||
}
|
||||
|
||||
singletonTest :: TestCase
|
||||
singletonTest =
|
||||
TestCase
|
||||
{ tcName = "SingletonTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/SingletonTest.java"
|
||||
, tcExpectedAST = SingletonAST.expectedAST
|
||||
, tcExpectedTAST = SingletonTAST.expectedTAST
|
||||
, tcExpectedABC = SingletonABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode SingletonABC.expectedABC
|
||||
}
|
||||
|
||||
whileTest :: TestCase
|
||||
whileTest =
|
||||
TestCase
|
||||
{ tcName = "WhileTest"
|
||||
, tcJavaFile = "src/Testsuite/javaFiles/WhileTest.java"
|
||||
, tcExpectedAST = WhileAST.expectedAST
|
||||
, tcExpectedTAST = WhileTAST.expectedTAST
|
||||
, tcExpectedABC = WhileABC.expectedABC
|
||||
, tcExpectedBytecode = toBytecode WhileABC.expectedABC
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
module Testsuite.ExecutableTests.Runner.ABC where
|
||||
|
||||
import Control.Exception (throwIO)
|
||||
import Codegen.ClassFile (generateClassFile)
|
||||
import Codegen.Lowerer (lowerClassFile)
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
import Testsuite.ExecutableTests.HarnessSupport (TestFailure(..))
|
||||
|
||||
runABCTest :: TestCase -> IO ()
|
||||
runABCTest tc =
|
||||
let actual = concatMap (lowerClassFile . generateClassFile) (tcExpectedTAST tc)
|
||||
in if actual == tcExpectedABC tc
|
||||
then pure ()
|
||||
else
|
||||
let body =
|
||||
tcName tc
|
||||
++ " ABC mismatch\nActual ABC:\n"
|
||||
++ show actual
|
||||
++ "\nExpected ABC:\n"
|
||||
++ show (tcExpectedABC tc)
|
||||
in throwIO $ TestFailure body
|
||||
@@ -0,0 +1,20 @@
|
||||
module Testsuite.ExecutableTests.Runner.AST where
|
||||
|
||||
import Control.Exception (throwIO)
|
||||
import Grammar.Parser
|
||||
import Grammar.Scanner
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
import Testsuite.ExecutableTests.HarnessSupport (TestFailure(..))
|
||||
|
||||
runASTTest :: TestCase -> IO ()
|
||||
runASTTest tc = do
|
||||
java <- readFile (tcJavaFile tc)
|
||||
let actual = parse . alexScanTokens $ java
|
||||
|
||||
if actual == tcExpectedAST tc
|
||||
then pure ()
|
||||
else throwIO $
|
||||
TestFailure $
|
||||
tcName tc ++ " AST mismatch\n"
|
||||
++ "Actual AST: " ++ show actual ++ "\n"
|
||||
++ "Expected AST: " ++ show (tcExpectedAST tc)
|
||||
@@ -0,0 +1,36 @@
|
||||
module Testsuite.ExecutableTests.Runner.Bytecode where
|
||||
|
||||
import Control.Exception (throwIO)
|
||||
import System.FilePath (takeFileName, replaceExtension)
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
import Testsuite.ExecutableTests.HarnessSupport (TestFailure(..))
|
||||
import Testsuite.ExecutableTests.Shared.BytecodeNormalize
|
||||
import Testsuite.ExecutableTests.Shared.ClassFileParser
|
||||
import Data.Word (Word8)
|
||||
import Data.List (intercalate)
|
||||
|
||||
bytesToHex :: [Word8] -> String
|
||||
bytesToHex bs = intercalate " " $ map (\b -> let h = showHex b in if length h == 1 then '0':h else h) (map fromIntegral bs)
|
||||
|
||||
showHex :: Int -> String
|
||||
showHex n = let hex = "0123456789ABCDEF" in [hex !! (n `div` 16), hex !! (n `mod` 16)]
|
||||
|
||||
runBytecodeTest :: TestCase -> IO ()
|
||||
runBytecodeTest tc = do
|
||||
let javaFilePath = tcJavaFile tc
|
||||
javaFileName = takeFileName javaFilePath
|
||||
classFilePath = "src/Testsuite/classFiles/" ++ replaceExtension javaFileName ".class"
|
||||
|
||||
actual <- parseMethodCodeBytesFromFile classFilePath
|
||||
let expected = tcExpectedBytecode tc
|
||||
|
||||
let nExpected = map (fmap normalizeBytecode) expected
|
||||
nActual = map (fmap normalizeBytecode) actual
|
||||
if nExpected == nActual
|
||||
then pure ()
|
||||
else
|
||||
let formatEntry (n, bs) = n ++ ": " ++ bytesToHex bs
|
||||
expectedLines = map formatEntry nExpected
|
||||
actualLines = map formatEntry nActual
|
||||
body = "bytecode mismatch for " ++ tcName tc ++ "\nExpected Bytecode:\n" ++ unlines expectedLines ++ "Actual Bytecode:\n" ++ unlines actualLines
|
||||
in throwIO $ TestFailure body
|
||||
@@ -0,0 +1,18 @@
|
||||
module Testsuite.ExecutableTests.Runner.TAST where
|
||||
|
||||
import Control.Exception (throwIO)
|
||||
import Typecheck.SemanticChecker (typeCheckClass)
|
||||
import Testsuite.ExecutableTests.TestCase
|
||||
import Testsuite.ExecutableTests.HarnessSupport (TestFailure(..))
|
||||
|
||||
runTASTTest :: TestCase -> IO ()
|
||||
runTASTTest tc =
|
||||
let actual = map (\c -> typeCheckClass c [] (tcExpectedAST tc)) (tcExpectedAST tc)
|
||||
|
||||
in if actual == tcExpectedTAST tc
|
||||
then pure ()
|
||||
else throwIO $
|
||||
TestFailure $
|
||||
tcName tc ++ " TAST mismatch\n"
|
||||
++ "Actual TAST: " ++ show actual ++ "\n"
|
||||
++ "Expected TAST: " ++ show (tcExpectedTAST tc)
|
||||
@@ -0,0 +1,17 @@
|
||||
module Testsuite.ExecutableTests.Shared.BytecodeNormalize where
|
||||
|
||||
import Data.Word (Word8)
|
||||
|
||||
-- | Normalize bytecode by replacing constant pool indices with a fixed placeholder (0xFF)
|
||||
normalizeBytecode :: [Word8] -> [Word8]
|
||||
normalizeBytecode [] = []
|
||||
normalizeBytecode (op:rest)
|
||||
-- 1-byte constant pool index instructions: ldc
|
||||
| op `elem` [0x12] && not (null rest) =
|
||||
op : 0xFF : normalizeBytecode (tail rest)
|
||||
-- 2-byte constant pool index instructions
|
||||
| op `elem` [0x13, 0x14, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8] && length rest >= 2 =
|
||||
let (_i1:_i2:restBytes) = rest
|
||||
in op : 0xFF : 0xFF : normalizeBytecode restBytes
|
||||
-- lookupswitch, tableswitch, wide, etc. could be handled here if needed
|
||||
| otherwise = op : normalizeBytecode rest
|
||||
@@ -0,0 +1,208 @@
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
|
||||
module Testsuite.ExecutableTests.Shared.ClassFileParser
|
||||
( parseClassFile
|
||||
, parseMethodCodeBytesFromFile
|
||||
) where
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.Map.Strict as Map
|
||||
import Data.Bits ((.|.), shiftL)
|
||||
import Data.Word (Word16, Word32, Word8)
|
||||
import Control.Monad (MonadFail)
|
||||
|
||||
parseClassFile :: BS.ByteString -> Either String [(String, [Word8])]
|
||||
parseClassFile bs =
|
||||
case runParser parseClassFileParser (BS.unpack bs) of
|
||||
Left e -> Left e
|
||||
Right (r, _) -> Right r
|
||||
|
||||
parseMethodCodeBytesFromFile :: FilePath -> IO [(String, [Word8])]
|
||||
parseMethodCodeBytesFromFile path = do
|
||||
bytes <- BS.readFile path
|
||||
case runParser parseClassFileParser (BS.unpack bytes) of
|
||||
Left err -> error ("Failed parsing class file '" ++ path ++ "': " ++ err)
|
||||
Right (methods, _) -> pure methods
|
||||
|
||||
newtype Parser a = Parser { runParser :: [Word8] -> Either String (a,[Word8]) }
|
||||
|
||||
instance Functor Parser where
|
||||
fmap f p = Parser $ \i -> do
|
||||
(a,r) <- runParser p i
|
||||
pure (f a,r)
|
||||
|
||||
instance Applicative Parser where
|
||||
pure x = Parser (\i -> Right (x,i))
|
||||
pf <*> px = Parser $ \i -> do
|
||||
(f,r1) <- runParser pf i
|
||||
(x,r2) <- runParser px r1
|
||||
pure (f x,r2)
|
||||
|
||||
instance Monad Parser where
|
||||
p >>= f = Parser $ \i -> do
|
||||
(a,r) <- runParser p i
|
||||
runParser (f a) r
|
||||
|
||||
instance MonadFail Parser where
|
||||
fail msg = Parser $ \_ -> Left msg
|
||||
|
||||
parseFail :: String -> Parser a
|
||||
parseFail msg = Parser $ \_ -> Left msg
|
||||
|
||||
u1 :: Parser Word8
|
||||
u1 = Parser $ \input ->
|
||||
case input of
|
||||
[] -> Left "Unexpected end of input while reading u1"
|
||||
(b : rest) -> Right (b, rest)
|
||||
|
||||
u2 :: Parser Word16
|
||||
u2 = do
|
||||
hi <- u1
|
||||
lo <- u1
|
||||
pure ((fromIntegral hi `shiftL` 8) .|. fromIntegral lo)
|
||||
|
||||
u4 :: Parser Word32
|
||||
u4 = do
|
||||
b1 <- u1
|
||||
b2 <- u1
|
||||
b3 <- u1
|
||||
b4 <- u1
|
||||
pure
|
||||
( (fromIntegral b1 `shiftL` 24)
|
||||
.|. (fromIntegral b2 `shiftL` 16)
|
||||
.|. (fromIntegral b3 `shiftL` 8)
|
||||
.|. fromIntegral b4
|
||||
)
|
||||
|
||||
takeN :: Int -> Parser [Word8]
|
||||
takeN n
|
||||
| n < 0 = parseFail "Negative takeN requested"
|
||||
| otherwise = Parser $ \input ->
|
||||
if length input < n
|
||||
then Left ("Unexpected end of input while reading " ++ show n ++ " bytes")
|
||||
else Right (splitAt n input)
|
||||
|
||||
skipN :: Int -> Parser ()
|
||||
skipN n = do
|
||||
_ <- takeN n
|
||||
pure ()
|
||||
|
||||
skipMembers :: Int -> Parser ()
|
||||
skipMembers 0 = pure ()
|
||||
skipMembers n = do
|
||||
_accessFlags <- u2
|
||||
_nameIndex <- u2
|
||||
_descriptorIndex <- u2
|
||||
attrCount <- fromIntegral <$> u2
|
||||
skipAttributes attrCount
|
||||
skipMembers (n - 1)
|
||||
|
||||
skipAttributes :: Int -> Parser ()
|
||||
skipAttributes 0 = pure ()
|
||||
skipAttributes n = do
|
||||
_attrNameIndex <- u2
|
||||
attrLen <- fromIntegral <$> u4
|
||||
skipN attrLen
|
||||
skipAttributes (n - 1)
|
||||
|
||||
parseClassFileParser :: Parser [(String, [Word8])]
|
||||
parseClassFileParser = do
|
||||
magic <- u4
|
||||
if magic /= 0xCAFEBABE
|
||||
then parseFail "Invalid class file magic"
|
||||
else pure ()
|
||||
|
||||
_minorVersion <- u2
|
||||
_majorVersion <- u2
|
||||
|
||||
cpCount <- fromIntegral <$> u2
|
||||
utf8Map <- parseConstantPool cpCount 1 Map.empty
|
||||
|
||||
_accessFlags <- u2
|
||||
_thisClass <- u2
|
||||
_superClass <- u2
|
||||
|
||||
interfacesCount <- fromIntegral <$> u2
|
||||
skipN (interfacesCount * 2)
|
||||
|
||||
fieldsCount <- fromIntegral <$> u2
|
||||
skipMembers fieldsCount
|
||||
|
||||
methodsCount <- fromIntegral <$> u2
|
||||
parseMethods utf8Map methodsCount
|
||||
|
||||
parseConstantPool :: Int -> Int -> Map.Map Int String -> Parser (Map.Map Int String)
|
||||
parseConstantPool cpCount idx utf8Map
|
||||
| idx >= cpCount = pure utf8Map
|
||||
| otherwise = do
|
||||
tag <- u1
|
||||
case tag of
|
||||
1 -> do
|
||||
len <- fromIntegral <$> u2
|
||||
bytes <- takeN len
|
||||
let value = map (toEnum . fromIntegral) bytes
|
||||
parseConstantPool cpCount (idx + 1) (Map.insert idx value utf8Map)
|
||||
3 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
4 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
5 -> skipN 8 >> parseConstantPool cpCount (idx + 2) utf8Map
|
||||
6 -> skipN 8 >> parseConstantPool cpCount (idx + 2) utf8Map
|
||||
7 -> skipN 2 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
8 -> skipN 2 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
9 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
10 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
11 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
12 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
15 -> skipN 3 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
16 -> skipN 2 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
17 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
18 -> skipN 4 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
19 -> skipN 2 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
20 -> skipN 2 >> parseConstantPool cpCount (idx + 1) utf8Map
|
||||
_ -> parseFail ("Unknown constant pool tag " ++ show tag)
|
||||
|
||||
parseMethods :: Map.Map Int String -> Int -> Parser [(String, [Word8])]
|
||||
parseMethods _ 0 = pure []
|
||||
parseMethods utf8Map n = do
|
||||
_accessFlags <- u2
|
||||
nameIndex <- fromIntegral <$> u2
|
||||
_descriptorIndex <- u2
|
||||
attrCount <- fromIntegral <$> u2
|
||||
|
||||
let methodName = Map.findWithDefault ("<unknown-" ++ show nameIndex ++ ">") nameIndex utf8Map
|
||||
|
||||
maybeCode <- parseMethodAttributes utf8Map attrCount
|
||||
rest <- parseMethods utf8Map (n - 1)
|
||||
case maybeCode of
|
||||
Nothing -> pure rest
|
||||
Just code -> pure ((methodName, code) : rest)
|
||||
|
||||
parseMethodAttributes :: Map.Map Int String -> Int -> Parser (Maybe [Word8])
|
||||
parseMethodAttributes _ 0 = pure Nothing
|
||||
parseMethodAttributes utf8Map n = do
|
||||
attrNameIndex <- fromIntegral <$> u2
|
||||
attrLen <- fromIntegral <$> u4
|
||||
let attrName = Map.findWithDefault "" attrNameIndex utf8Map
|
||||
|
||||
current <-
|
||||
if attrName == "Code"
|
||||
then parseCodeAttribute attrLen
|
||||
else skipN attrLen >> pure Nothing
|
||||
|
||||
next <- parseMethodAttributes utf8Map (n - 1)
|
||||
pure (pickFirst current next)
|
||||
|
||||
pickFirst :: Maybe a -> Maybe a -> Maybe a
|
||||
pickFirst (Just x) _ = Just x
|
||||
pickFirst Nothing y = y
|
||||
|
||||
parseCodeAttribute :: Int -> Parser (Maybe [Word8])
|
||||
parseCodeAttribute _declaredLength = do
|
||||
_maxStack <- u2
|
||||
_maxLocals <- u2
|
||||
codeLen <- fromIntegral <$> u4
|
||||
codeBytes <- takeN codeLen
|
||||
exceptionTableLen <- fromIntegral <$> u2
|
||||
skipN (exceptionTableLen * 8)
|
||||
attrCount <- fromIntegral <$> u2
|
||||
skipAttributes attrCount
|
||||
pure (Just codeBytes)
|
||||
@@ -0,0 +1,16 @@
|
||||
module Testsuite.ExecutableTests.TestCase where
|
||||
|
||||
import Grammar.AST (Class)
|
||||
import Grammar.TAST (TypedClass)
|
||||
import Codegen.Lowerer (BtcProgram)
|
||||
import Data.Word (Word8)
|
||||
|
||||
data TestCase = TestCase
|
||||
{ tcName :: String
|
||||
, tcJavaFile :: FilePath
|
||||
|
||||
, tcExpectedAST :: [Class]
|
||||
, tcExpectedTAST :: [TypedClass]
|
||||
, tcExpectedABC :: [(String, BtcProgram)]
|
||||
, tcExpectedBytecode :: [(String, [Word8])]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
runghc -isrc src/Testsuite/ExecutableTests/Main.hs WhileTest
|
||||
runghc -isrc src/Testsuite/ExecutableTests/Main.hs
|
||||
|
||||
cabal run compiler src/Testsuite/javaFiles/ArithmeticTest.java
|
||||
cabal run compiler src/Testsuite/javaFiles/ConstructorTest.java
|
||||
# ... etc for all individual test files
|
||||
|
||||
java -cp /path/to/classFiles Main
|
||||
|
||||
cd src/Testsuite/classFiles
|
||||
java -cp . Main
|
||||
|
||||
|
||||
get lexical test errors:
|
||||
runghc -isrc src/Testsuite/ExecutableTests/Main.hs | grep --line-buffered -i -n -B1 'Lexical' | grep 'RUN'
|
||||
@@ -0,0 +1,100 @@
|
||||
module Testsuite.TastFiles.AllSyntaxTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"AllSyntaxTest"
|
||||
[ Field "int" "x" Nothing
|
||||
, Field "int" "counter" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "initial")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x" "int") (LocalOrFieldVar "initial" "int") "int") "void"
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "counter" "int") (Integer 0 "int") "int") "void"
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "counter" "int") (Binary Add (LocalOrFieldVar "counter" "int") (Integer 1 "int") "int") "int") "void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"inc"
|
||||
[]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x" "int") (Binary Add (LocalOrFieldVar "x" "int") (Integer 1 "int") "int") "int") "void"
|
||||
, Return (Just (LocalOrFieldVar "x" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"inc"
|
||||
[("int", "delta")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "x" "int") (Binary Add (LocalOrFieldVar "x" "int") (LocalOrFieldVar "delta" "int") "int") "int") "void"
|
||||
, Return (Just (LocalOrFieldVar "x" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"sumUpTo"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "s" "int"
|
||||
, Block
|
||||
[ LocalVarDecl "int" "i" "int"
|
||||
, While
|
||||
(Binary CompLessOrEqual (LocalOrFieldVar "i" "int") (LocalOrFieldVar "n" "int") "boolean")
|
||||
( Block
|
||||
[ Block
|
||||
[ StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "s" "int")
|
||||
(Binary Add (LocalOrFieldVar "s" "int") (LocalOrFieldVar "i" "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
, StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "i" "int")
|
||||
(Binary Add (LocalOrFieldVar "i" "int") (Integer 1 "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "s" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"boolean"
|
||||
"predicate"
|
||||
[("char", "c")]
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
Or
|
||||
(Binary CompEqual (LocalOrFieldVar "c" "char") (Char 'a' "char") "boolean")
|
||||
(Binary CompEqual (LocalOrFieldVar "c" "char") (Char 'b' "char") "boolean")
|
||||
"boolean"
|
||||
)
|
||||
)
|
||||
"boolean"
|
||||
]
|
||||
"boolean"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,57 @@
|
||||
module Testsuite.TastFiles.ArithmeticTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ArithmeticTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"basic"
|
||||
[("int", "a"), ("int", "b"), ("int", "c")]
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
Subtract
|
||||
(Binary Add (LocalOrFieldVar "a" "int") (LocalOrFieldVar "b" "int") "int")
|
||||
( Binary
|
||||
Modulo
|
||||
( Binary
|
||||
Divide
|
||||
(Binary Multiply (LocalOrFieldVar "c" "int") (LocalOrFieldVar "a" "int") "int")
|
||||
(LocalOrFieldVar "b" "int")
|
||||
"int"
|
||||
)
|
||||
(LocalOrFieldVar "c" "int")
|
||||
"int"
|
||||
)
|
||||
"int"
|
||||
)
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"boolean"
|
||||
"logic"
|
||||
[("boolean", "a"), ("boolean", "b"), ("boolean", "c")]
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
And
|
||||
(Unary Not (LocalOrFieldVar "a" "boolean") "boolean")
|
||||
(Binary Or (LocalOrFieldVar "c" "boolean") (LocalOrFieldVar "b" "boolean") "boolean")
|
||||
"boolean"
|
||||
)
|
||||
)
|
||||
"boolean"
|
||||
]
|
||||
"boolean"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
module Testsuite.TastFiles.CombinedControlTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"CombinedControlTest"
|
||||
[ Field "int" "field" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "v")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (LocalOrFieldVar "field" "int") (LocalOrFieldVar "v" "int") "int") "void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"compute"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "i" "int"
|
||||
, LocalVarDecl "int" "acc" "int"
|
||||
, While
|
||||
(Binary CompLessThan (LocalOrFieldVar "i" "int") (LocalOrFieldVar "field" "int") "boolean")
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (Binary Modulo (LocalOrFieldVar "i" "int") (Integer 2 "int") "int") (Integer 0 "int") "boolean")
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "acc" "int") (Binary Add (LocalOrFieldVar "acc" "int") (LocalOrFieldVar "i" "int") "int") "int") "void"] "void")
|
||||
(Just (Block [StmtExprStmt (Assign (LocalOrFieldVar "acc" "int") (Binary Subtract (LocalOrFieldVar "acc" "int") (LocalOrFieldVar "i" "int") "int") "int") "void"] "void"))
|
||||
"void"
|
||||
, StmtExprStmt (Assign (LocalOrFieldVar "i" "int") (Binary Add (LocalOrFieldVar "i" "int") (Integer 1 "int") "int") "int") "void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "acc" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
module Testsuite.TastFiles.ConstructorOverloadTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ConstructorOverloadTest"
|
||||
[Field "int" "a" (Just (Integer 42 "int"))]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[]
|
||||
(Block [] "void"),
|
||||
Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "a")]
|
||||
(Block [StmtExprStmt (Assign (InstVar (This "ConstructorOverloadTest") "a" "int") (LocalOrFieldVar "a" "int") "int") "void"] "void")
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,16 @@
|
||||
module Testsuite.TastFiles.ConstructorTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ConstructorTest"
|
||||
[Field "int" "a" (Just (Unary Negate (Integer 1 "int") "int"))]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "initial_value")]
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "a" "int") (LocalOrFieldVar "initial_value" "int") "int") "void"] "void")
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
module Testsuite.TastFiles.EmptyTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"EmptyTest"
|
||||
[]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
module Testsuite.TastFiles.ExpressionTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ExpressionTest"
|
||||
[]
|
||||
[ Method
|
||||
"boolean"
|
||||
"shortCircuit"
|
||||
[("int", "a"), ("int", "b")]
|
||||
( Block
|
||||
[ LocalVarDecl "boolean" "res" "boolean"
|
||||
, Return (Just (LocalOrFieldVar "res" "boolean")) "boolean"
|
||||
]
|
||||
"boolean"
|
||||
)
|
||||
, Method
|
||||
"char"
|
||||
"charArithmetic"
|
||||
[("char", "c"), ("int", "offset")]
|
||||
( Block
|
||||
[ LocalVarDecl "char" "d" "char"
|
||||
, Return (Just (LocalOrFieldVar "d" "char")) "char"
|
||||
]
|
||||
"char"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
module Testsuite.TastFiles.FieldsTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"FieldsTest"
|
||||
[ Field "int" "a" Nothing,
|
||||
Field "int" "b" (Just (Integer 42 "int"))
|
||||
]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,60 @@
|
||||
module Testsuite.TastFiles.IfTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST :: [TypedClass]
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"IfTest"
|
||||
[]
|
||||
[ Method
|
||||
"boolean"
|
||||
"ifElseTest"
|
||||
[("int", "x")]
|
||||
( Block
|
||||
[ If
|
||||
( Binary CompLessThan
|
||||
(LocalOrFieldVar "x" "int")
|
||||
(Integer 0 "int")
|
||||
"boolean"
|
||||
)
|
||||
( Block
|
||||
[ Return (Just (Bool False "boolean")) "boolean" ]
|
||||
"boolean"
|
||||
)
|
||||
( Just
|
||||
( If
|
||||
( Binary CompEqual
|
||||
(LocalOrFieldVar "x" "int")
|
||||
(Integer 0 "int")
|
||||
"boolean"
|
||||
)
|
||||
( Block
|
||||
[ Return (Just (Bool True "boolean")) "boolean" ]
|
||||
"boolean"
|
||||
)
|
||||
( Just
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary CompGreaterThan
|
||||
(LocalOrFieldVar "x" "int")
|
||||
(Integer 10 "int")
|
||||
"boolean"
|
||||
)
|
||||
)
|
||||
"boolean"
|
||||
]
|
||||
"boolean"
|
||||
)
|
||||
)
|
||||
"boolean"
|
||||
)
|
||||
)
|
||||
"boolean"
|
||||
]
|
||||
"boolean"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,78 @@
|
||||
module Testsuite.TastFiles.LoopTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"LoopTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"factorial"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "tally" "int"
|
||||
, Block
|
||||
[ LocalVarDecl "int" "i" "int"
|
||||
, While
|
||||
(Binary CompLessOrEqual (LocalOrFieldVar "i" "int") (LocalOrFieldVar "n" "int") "boolean")
|
||||
( Block
|
||||
[ Block
|
||||
[ StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "tally" "int")
|
||||
(Binary Multiply (LocalOrFieldVar "tally" "int") (LocalOrFieldVar "i" "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
, StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "i" "int")
|
||||
(Binary Add (LocalOrFieldVar "i" "int") (Integer 1 "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "tally" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"weirdFor"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "k" "int"
|
||||
, Block
|
||||
[ EmptyStmt "void"
|
||||
, While
|
||||
(Binary CompLessThan (LocalOrFieldVar "k" "int") (Integer 5 "int") "boolean")
|
||||
( Block
|
||||
[ Block [] "void"
|
||||
, StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "k" "int")
|
||||
(Binary Add (LocalOrFieldVar "k" "int") (Integer 1 "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "k" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
module Testsuite.TastFiles.MaliciousTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"MaliciousTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"cursedFormatting"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "n" "int") (Integer 0 "int") "boolean")
|
||||
(Block [Return (Just (Integer 0 "int")) "int"] "int")
|
||||
( Just
|
||||
( If
|
||||
(Binary CompEqual (LocalOrFieldVar "n" "int") (Integer 1 "int") "boolean")
|
||||
(Block [Return (Just (Integer 1 "int")) "int"] "int")
|
||||
(Just (Block [Return (Just (Integer 2 "int")) "int"] "int"))
|
||||
"int"
|
||||
)
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
module Testsuite.TastFiles.MethodOverloadTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"MethodOverloadTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"MethodOverload"
|
||||
[]
|
||||
(Block [Return (Just (Integer 42 "int")) "int"] "int"),
|
||||
Method
|
||||
"int"
|
||||
"MethodOverload"
|
||||
[("int", "a")]
|
||||
(Block [Return (Just (Binary Add (Integer 42 "int") (LocalOrFieldVar "a" "int") "int")) "int"] "int")
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
module Testsuite.TastFiles.MultiClassTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"MultiClassTest"
|
||||
[]
|
||||
[],
|
||||
Class
|
||||
"Helper"
|
||||
[Field "int" "v" Nothing]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "v0")]
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "v" "int") (LocalOrFieldVar "v0" "int") "int") "void"] "void"),
|
||||
Method
|
||||
"int"
|
||||
"doubleIt"
|
||||
[]
|
||||
(Block [Return (Just (Binary Multiply (LocalOrFieldVar "v" "int") (Integer 2 "int") "int")) "int"] "int")
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,17 @@
|
||||
module Testsuite.TastFiles.MultipleClassesTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"MultipleClassesTest"
|
||||
[ Field "AnotherTestClass" "a" (Just (StmtExprExpr (New "AnotherTestClass" [] "AnotherTestClass") "AnotherTestClass"))
|
||||
]
|
||||
[]
|
||||
, Class
|
||||
"AnotherTestClass"
|
||||
[ Field "int" "a" (Just (Integer 42 "int"))
|
||||
]
|
||||
[]
|
||||
]
|
||||
@@ -0,0 +1,110 @@
|
||||
module Testsuite.TastFiles.RecursionTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"RecursionTest"
|
||||
[ Field "int" "value" (Just (Integer 0 "int"))
|
||||
, Field "RecursionTest" "child" (Just (Null "null"))
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ StmtExprStmt (Assign (InstVar (This "RecursionTest") "value" "int") (LocalOrFieldVar "n" "int") "int") "void"
|
||||
, If
|
||||
(Binary CompGreaterThan (LocalOrFieldVar "n" "int") (Integer 0 "int") "boolean")
|
||||
( Block
|
||||
[ StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "child" "RecursionTest")
|
||||
(StmtExprExpr
|
||||
(New "RecursionTest" [Binary Subtract (LocalOrFieldVar "n" "int") (Integer 1 "int") "int"] "RecursionTest")
|
||||
"RecursionTest"
|
||||
)
|
||||
"RecursionTest"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
Nothing
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"fibonacci"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompLessThan (LocalOrFieldVar "n" "int") (Integer 2 "int") "boolean")
|
||||
(Block [Return (Just (LocalOrFieldVar "n" "int")) "int"] "int")
|
||||
( Just
|
||||
( Block
|
||||
[ Return
|
||||
( Just
|
||||
( Binary
|
||||
Add
|
||||
(StmtExprExpr (MethodCall (This "RecursionTest") "fibonacci" [Binary Subtract (LocalOrFieldVar "n" "int") (Integer 1 "int") "int"] "int") "int")
|
||||
(StmtExprExpr (MethodCall (This "RecursionTest") "fibonacci" [Binary Subtract (LocalOrFieldVar "n" "int") (Integer 2 "int") "int"] "int") "int")
|
||||
"int"
|
||||
)
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"ackermann"
|
||||
[("int", "m"), ("int", "n")]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "m" "int") (Integer 0 "int") "boolean")
|
||||
(Return (Just (Binary Add (LocalOrFieldVar "n" "int") (Integer 1 "int") "int")) "int")
|
||||
Nothing
|
||||
"int"
|
||||
, If
|
||||
(Binary CompEqual (LocalOrFieldVar "n" "int") (Integer 0 "int") "boolean")
|
||||
(Return (Just (StmtExprExpr (MethodCall (This "RecursionTest") "ackermann" [Binary Subtract (LocalOrFieldVar "m" "int") (Integer 1 "int") "int", Integer 1 "int"] "int") "int")) "int")
|
||||
Nothing
|
||||
"int"
|
||||
, Return
|
||||
( Just
|
||||
( StmtExprExpr
|
||||
( MethodCall
|
||||
(This "RecursionTest")
|
||||
"ackermann"
|
||||
[ Binary Subtract (LocalOrFieldVar "m" "int") (Integer 1 "int") "int"
|
||||
, StmtExprExpr
|
||||
(MethodCall
|
||||
(This "RecursionTest")
|
||||
"ackermann"
|
||||
[ LocalOrFieldVar "m" "int"
|
||||
, Binary Subtract (LocalOrFieldVar "n" "int") (Integer 1 "int") "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
"int"
|
||||
)
|
||||
)
|
||||
"int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
module Testsuite.TastFiles.ReturnTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST :: [TypedClass]
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ReturnTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"main"
|
||||
[]
|
||||
( Block
|
||||
[ Return (Just (Integer 42 "int")) "int" ]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
module Testsuite.TastFiles.ShenaniganceTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"ShenaniganceTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"testAssignment"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "x" "int"
|
||||
, LocalVarDecl "int" "y" "int"
|
||||
, Return (Just (LocalOrFieldVar "y" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
, Method
|
||||
"int"
|
||||
"divEqual"
|
||||
[]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "x" "int"
|
||||
, StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "x" "int")
|
||||
(Binary Divide (LocalOrFieldVar "x" "int") (Integer 4 "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "x" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
module Testsuite.TastFiles.SingletonTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..), UnaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"SingletonTest"
|
||||
[ Field "SingletonTest" "instance" Nothing
|
||||
]
|
||||
[ Method
|
||||
"void"
|
||||
"<init>"
|
||||
[]
|
||||
(Block [] "void")
|
||||
, Method
|
||||
"SingletonTest"
|
||||
"getInstance"
|
||||
[]
|
||||
( Block
|
||||
[ If
|
||||
(Binary CompEqual (LocalOrFieldVar "instance" "SingletonTest") (Null "null") "boolean")
|
||||
(Block [StmtExprStmt (Assign (LocalOrFieldVar "instance" "SingletonTest") (StmtExprExpr (New "SingletonTest" [] "SingletonTest") "SingletonTest") "SingletonTest") "void"] "void")
|
||||
Nothing
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "instance" "SingletonTest")) "SingletonTest"
|
||||
]
|
||||
"SingletonTest"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,43 @@
|
||||
module Testsuite.TastFiles.WhileTestTAST (expectedTAST) where
|
||||
|
||||
import Grammar.AST (BinaryOperator (..))
|
||||
import Grammar.TAST
|
||||
|
||||
expectedTAST :: [TypedClass]
|
||||
expectedTAST =
|
||||
[ Class
|
||||
"WhileTest"
|
||||
[]
|
||||
[ Method
|
||||
"int"
|
||||
"whileLoopTest"
|
||||
[("int", "n")]
|
||||
( Block
|
||||
[ LocalVarDecl "int" "sum" "int"
|
||||
, While
|
||||
(Binary CompGreaterThan (LocalOrFieldVar "n" "int") (Integer 0 "int") "boolean")
|
||||
( Block
|
||||
[ StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "sum" "int")
|
||||
(Binary Add (LocalOrFieldVar "sum" "int") (LocalOrFieldVar "n" "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
, StmtExprStmt
|
||||
(Assign
|
||||
(LocalOrFieldVar "n" "int")
|
||||
(Binary Subtract (LocalOrFieldVar "n" "int") (Integer 1 "int") "int")
|
||||
"int"
|
||||
)
|
||||
"void"
|
||||
]
|
||||
"void"
|
||||
)
|
||||
"void"
|
||||
, Return (Just (LocalOrFieldVar "sum" "int")) "int"
|
||||
]
|
||||
"int"
|
||||
)
|
||||
]
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
[("basic",BtcProgram [BtcLine {lineNumber = 0, instruction = ILoad 0},BtcLine {lineNumber = 1, instruction = ILoad 1},BtcLine {lineNumber = 2, instruction = IAdd},BtcLine {lineNumber = 3, instruction = ILoad 2},BtcLine {lineNumber = 4, instruction = ILoad 0},BtcLine {lineNumber = 5, instruction = IMul},BtcLine {lineNumber = 6, instruction = ILoad 1},BtcLine {lineNumber = 7, instruction = ISub},BtcLine {lineNumber = 8, instruction = ILoad 2},BtcLine {lineNumber = 9, instruction = ISub},BtcLine {lineNumber = 10, instruction = IReturn}]),("logic",BtcProgram [BtcLine {lineNumber = 0, instruction = ILoad 0},BtcLine {lineNumber = 1, instruction = ILoad 2},BtcLine {lineNumber = 2, instruction = ILoad 1},BtcLine {lineNumber = 3, instruction = IAdd},BtcLine {lineNumber = 4, instruction = IAdd},BtcLine {lineNumber = 5, instruction = IReturn}])]
|
||||
@@ -1 +0,0 @@
|
||||
[]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user