106 Commits

Author SHA1 Message Date
Vectabyte 5643aa703e removed unneeded .class files 2026-05-30 15:21:24 +02:00
Vectabyte 74f68cb525 Bytecode Adjustments 2026-05-20 15:42:59 +02:00
Vectabyte f10f7883dd test adjustments and fixes 2026-05-20 14:19:04 +02:00
Vectabyte a8c6a056da Fixed Lexer Errors with Tests 2026-05-20 10:56:58 +02:00
Felix Weglehner c7796b4f25 Added constructor support to parser 2026-05-20 10:27:00 +02:00
Vectabyte cc2d157674 Test Fixes 2026-05-20 10:03:18 +02:00
Vectabyte d576e64534 updated registry 2026-05-20 09:25:52 +02:00
Vectabyte cec34d1d9e More Tests! 2026-05-20 09:25:44 +02:00
Vectabyte 69ae49a346 updated tests and added more 2026-05-15 11:25:18 +02:00
Vectabyte e43a783d33 updated corresponding ast and tast 2026-05-14 17:59:04 +02:00
Vectabyte 0496e6e1b4 Updated test cases to comply with constraints 2026-05-14 17:45:33 +02:00
Vectabyte 4f5e4febdf More test's, removed old harness 2026-05-14 16:52:43 +02:00
Konstantin Fastovski ffae200d3c fix merge conflict residue 2026-05-13 15:56:10 +02:00
Konstantin Fastovski 85b93a604c properly handle large integers in constpool 2026-05-13 15:54:49 +02:00
Vectabyte 3ffac1ffe6 Merge remote-tracking branch 'origin/main' into test-creation 2026-05-13 15:42:06 +02:00
Silas 3cf088b818 update ConstPool 2026-05-13 15:37:10 +02:00
Vectabyte e86389baf8 overhauled test suite 2026-05-13 15:33:49 +02:00
Vectabyte 6aedcfe4e1 Merge remote-tracking branch 'origin/main' into test-creation 2026-05-13 14:18:54 +02:00
Felix fe71942a65 Added Maybe Stmt to LocalVarDecl to allow in place assignment
Added Operator Assignment Statements (test *= 2)
Added for loop support -> While in the AST
2026-05-13 14:18:25 +02:00
Vectabyte a2ebe25901 Merge remote-tracking branch 'origin/main' into test-creation 2026-05-13 12:12:43 +02:00
Konstantin Fastovski 8ac6223c6b add BIPush and SIPush Instructions 2026-05-13 12:12:21 +02:00
Vectabyte 9d4106aee8 Folder rename 2026-05-13 12:11:09 +02:00
Vectabyte 95a80ca5d3 included constant pool index strip 2026-05-13 12:01:59 +02:00
Vectabyte b0abf5ee72 Merge remote-tracking branch 'origin/main' into test-creation 2026-05-13 11:39:33 +02:00
Vectabyte 69b8bcba4d adjusted and added tests 2026-05-13 11:36:47 +02:00
timb 8ecda70a5f feat: add for loops to parser 2026-05-13 11:25:35 +02:00
LeonProgrammiert 309d52715a Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-13 10:57:03 +02:00
LeonProgrammiert 0f2469f007 Fixed symtab in semantik checker 2026-05-13 10:56:50 +02:00
Konstantin Fastovski bfd70838aa fix test.sh 2026-05-13 10:50:00 +02:00
Konstantin Fastovski e48012c3ed fix Makefile 2026-05-13 10:41:15 +02:00
Konstantin Fastovski fc2b31693d fix test.sh 2026-05-13 10:40:28 +02:00
Vectabyte 1bc9babd4f Merge remote-tracking branch 'origin/main' into test-creation 2026-05-13 10:35:02 +02:00
Vectabyte 604db760ac added missing type 2026-05-13 10:34:36 +02:00
Vectabyte 4e24b2fb8a Test Fixes 2026-05-13 10:29:47 +02:00
Konstantin Fastovski 94e23b57fd add Makefile 2026-05-13 10:06:28 +02:00
Vectabyte 22fd6733f0 missing test cases 2026-05-13 10:05:29 +02:00
Vectabyte 62f42611bc txt for test commands 2026-05-13 10:01:35 +02:00
Vectabyte 2e601b86d5 more tests 2026-05-13 09:47:52 +02:00
mo 2141bd44cb Merge branch 'main' into feature/codegen-testing 2026-05-13 09:29:14 +02:00
Vectabyte 3ac33af1b5 Added another test case 2026-05-12 22:41:36 +02:00
Vectabyte 9046e3621b Reworked Executeable Test setup 2026-05-12 22:35:26 +02:00
Vectabyte 7c0f49ccca fixed java files 2026-05-12 22:29:11 +02:00
Vectabyte 6e16a502aa adjusted output of test cases 2026-05-12 22:15:04 +02:00
Vectabyte b45502a550 added harnesses to test suite 2026-05-12 21:55:45 +02:00
Vectabyte 83ff583c1c generated class files with normal java compiler 2026-05-12 21:13:59 +02:00
Vectabyte f19d6f6d39 added more executeable tests 2026-05-12 21:10:15 +02:00
mo cbd7df780a test: add Runner class to execute and test generated bytecode 2026-05-09 19:25:23 +02:00
mo 9d405fac61 test: add comment in test.sh for command "how to inspect a diff" 2026-05-09 17:34:19 +02:00
mo dde92cc64d feat: add bytecode generation for primitive field initializers in constructors 2026-05-09 17:34:02 +02:00
mo c8261b361a test: add command as note in test.sh 2026-05-08 20:42:26 +02:00
mo d0d37dd05e test: compare bytecode with javap -c to ignore CP ordering differences 2026-05-08 20:41:26 +02:00
mo e8ab0ed082 test: add javap-based test script to compare output against javac 2026-05-08 20:25:18 +02:00
mo 544774d8b9 feat: generate default <init> constructor with super() call 2026-05-08 20:25:07 +02:00
mo f2cc603690 feat: serialize ClassFile to binary and write .class files to out/ 2026-05-08 20:10:38 +02:00
mo a0f5d736f9 fix: bad CP index in ClassInfo, missing import in Lowerer 2026-05-08 20:07:58 +02:00
mo 8416f1b9c8 fix classfile & constpool errors 2026-05-08 15:53:06 +02:00
timb 245e70169e fix tiny bug && cleanup 2026-05-06 17:21:03 +02:00
LeonProgrammiert 8497b949a4 Updated FieldDecl in Semantik Checker 2026-05-06 16:58:36 +02:00
timb 251d8daa0f feat: add optional assignment on field declaration 2026-05-06 15:04:49 +02:00
LeonProgrammiert 1ad70c0b00 Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-06 14:12:34 +02:00
LeonProgrammiert 7f6e8f5cb5 Fix
Co-authored-by: Copilot <copilot@github.com>
2026-05-06 14:12:27 +02:00
mo 88e9b545eb chore: remove src/Main 2026-05-06 14:05:15 +02:00
timb 11fda5eaa7 feat: add visibility in scanner and lexer (no logic changes yet); rename
folders to support haskell module structure
2026-05-06 14:01:12 +02:00
Konstantin Fastovski 1a153200fa update workflow in Main.hs 2026-05-06 13:51:03 +02:00
LeonProgrammiert 815388b842 Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-06 13:28:00 +02:00
LeonProgrammiert 22e238317c Added classes, methods and fields 2026-05-06 13:27:58 +02:00
Konstantin Fastovski 5d48938221 get shit to compile 2026-05-06 13:23:06 +02:00
Konstantin Fastovski 44c1032e15 extract shared types for ClassFile and ConstPool 2026-05-06 13:15:26 +02:00
Konstantin Fastovski 842149be5e remove unused stuff from Main 2026-05-06 12:49:38 +02:00
Konstantin Fastovski 48b6270fd0 fix search functions 2026-05-06 12:27:48 +02:00
LeonProgrammiert b668fc94ff Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-06 11:31:55 +02:00
LeonProgrammiert a829814cd6 Finished typeCheckStmt, typeCheckExpr and typeCheckStmtExpr
Co-authored-by: Copilot <copilot@github.com>
2026-05-06 11:31:52 +02:00
Konstantin Fastovski 66e0efba81 update generateClassFile signature and import generateConstPool 2026-05-06 11:27:13 +02:00
Konstantin Fastovski 31248ecc97 get shit to compile and update Main.hs 2026-05-06 11:21:17 +02:00
Silas ac60aeba3e fix: new method name 2026-05-06 11:14:50 +02:00
Silas b833d6ebe0 fix: cleaner code 2026-05-06 11:13:02 +02:00
Konstantin Fastovski 3f0e00ac63 fix: pass typed Class into generateClassfile 2026-05-06 11:00:50 +02:00
Konstantin Fastovski 4370ec3c1f add makeMethods function 2026-05-06 10:58:35 +02:00
Konstantin Fastovski 162bed1b12 fix: add constPool to necessary makefunction signatures 2026-05-06 10:58:35 +02:00
Silas e91fac7060 add ConstPool building method 2026-05-06 10:57:24 +02:00
LeonProgrammiert 0eb8c64fc6 Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-06 10:43:23 +02:00
LeonProgrammiert f96627fcc9 Typechecked WhileStmt 2026-05-06 10:43:20 +02:00
Vectabyte b5ddd0b5c9 Merge branch 'main' of https://gitea.hb.dhbw-stuttgart.de/mo/Compoiler 2026-05-06 10:38:14 +02:00
Vectabyte 531f5d7f7f fix: fixed missing test cases in main
Co-authored-by: Copilot <copilot@github.com>
2026-05-06 10:36:57 +02:00
Konstantin Fastovski 5a16f08ccc add generateClassFile funciton skeleton 2026-05-06 10:29:39 +02:00
Konstantin Fastovski e5eb3a9792 fix: remove Type from end of TypedClass, etc. 2026-05-06 10:21:19 +02:00
LeonProgrammiert 8e3b978ba4 Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-05-06 09:44:42 +02:00
LeonProgrammiert 1b2ae2ae22 Typed classes 2026-05-06 09:44:40 +02:00
Vectabyte d9b7ba40bc abc files
Co-authored-by: Copilot <copilot@github.com>
2026-05-05 00:41:07 +02:00
Vectabyte 03e0571f4e Moved more files around 2026-05-05 00:11:28 +02:00
Vectabyte 4978de5220 Moved Files 2026-05-05 00:09:31 +02:00
Vectabyte b80b71936a Merge pull request 'Initial Test Cases' (#3) from feature/test-cases into main
Reviewed-on: #3
2026-05-04 17:18:39 +00:00
Vectabyte 22de50b77e Merge branch 'main' into feature/test-cases 2026-05-04 17:18:29 +00:00
Vectabyte e84550025c Initial Test Cases 2026-05-04 19:16:34 +02:00
Silas 8470ab2d94 new ConstPool first steps 2026-04-29 16:29:28 +02:00
Konstantin Fastovski 1ad8aface9 Merge branch 'feature/create-codegen-skeleton-and-add-'return-int'-as-example' 2026-04-29 16:26:16 +02:00
Konstantin Fastovski daa741a090 Implement Classfile datatype, Lowerer and (untested) Serializer 2026-04-29 16:25:01 +02:00
Konstantin Fastovski e81ceb454f feat: moved ai generated files to subdirectory 2026-04-29 15:07:00 +02:00
LeonProgrammiert 87db9f6e23 Merge branch 'main' of ssh://gitea.hb.dhbw-stuttgart.de:2222/mo/Compoiler 2026-04-29 14:21:25 +02:00
LeonProgrammiert a447fad905 feat: updated AST, TAST and getType Methods 2026-04-29 14:21:22 +02:00
Felix b964bdda1b Merge branch 'feature/operators' 2026-04-29 11:28:04 +02:00
timb 2f908d1df1 feat: update typed abstract syntax 2026-04-29 11:13:37 +02:00
Silas 40e84e45f6 Merge branch 'main' of https://gitea.hb.dhbw-stuttgart.de/mo/Compoiler 2026-04-29 11:04:47 +02:00
tym 56d43bac38 Merge pull request 'Added operators' (#2) from feature/operators into main
Reviewed-on: #2
2026-04-29 08:05:11 +00:00
Silas 9230042b25 feat: add Konstantenpool 2026-04-29 09:29:12 +02:00
Konstantin Fastovski 76c4cb677c feat: codegen skeleton 2026-04-27 16:03:04 +02:00
129 changed files with 5113 additions and 103 deletions
+5
View File
@@ -31,3 +31,8 @@ cabal.project.local~
hie.yaml
src/Grammar/Scanner.hs
src/Grammar/Parser.hs
src/Grammar/Parser.info
src/Main
out/
mine.txt
ref.txt
+81
View File
@@ -0,0 +1,81 @@
# Compilerbau
# Prüfungsleistung
## Spezifikation
Deklarationen: • Σ: EingabeAlphabet
- JC: Menge aller syntaktisch korrekten JavaKlassen mit folgenden Einschränkungen:
- keine generischen Klassen
- keine abstrakten Klassen
- keine Vererbung
- keine Interfaces
- keine Threads
- keine Exceptions
- keine Arrays
- als Basistypen sind nur int, boolean und char zugelassen
- keine Packages
- keine Imports
- keine LambdaExpressions
- BC: Menge aller BytecodeFiles
Eingabe: p∈Σ∗
Vorbedingung: ∅
Ausgabe: bc∈BC∗∪{error}
Nachbedingungen: • falls p∈(JC), so ist bc∈(BC)und p wird nach bc übersetzt wie es durch die Sprache Java definiert ist.
- falls p !∈(JC), so ist bc=error.
## Vorgehen
Arbeitsteam:Der JavaCompiler wird in einem Team von 5-7 Personen erstellt. Das
Team wird nochmals unterteilt:
- Gemeinsame Aufgabe
GIT-Repository: Einrichten eines GIT-Repositories auf den DHBW GITEA-Server
Abstrakte Syntax: Aufbau der abstrakten Syntax aus dem Parsetree
Dokumentation: Erstellen der Dokumentation
- Scannen/Parsen/Grammatik (12 Personen)
Scannen: alexFile oder Scanner von Hand programmieren
Grammatik (nur bei Bearbeitung durch 2 Personen):Erstellen einer Mini-Java-Grammatik an Hand der Spezifikation
Parsen:Erstellen des happyFiles oder des KombinatorParsers und Aufbau des abstrakten Syntaxbaums
- Semantische Analyse:Typisierung der abstrakten Syntax(1 Person)
Typisierung: Typisierung der abstrakten Syntax
- Codeerzeugung (2-3 Personen):
- Aufbau eines abstrakten ClassFiles (1 Person)
- Konstantenpool (1 Person)
- Nur bei Bearbeitung durch 3 Personen:Umwandlung des ClassFiles in Bytecode (1 Person)
- Tester (1 Person)
- Testsuite von JavaFiles, die alle implementierten Features abdecken.
- Händische Übersetzung aller Java-Files der Testsuite in die abstrakte Syntax (als TestEingaben für den Typ-Checker)
- Händische Übersetzung aller Testfälle der abstrakten Syntax in getypte abstrakte Syntax (als TestEingaben für den Code-Generierer).
- Händische Übersetzung aller Testfälle der getypten abstrakten Syntax in abstrakten Bytecode.
- Automatische Tests, die die jeweiligen Testsuite mit den implementierten Funktionen des Teams vergleichen
## Prüfungsleistung
Die Arbeitsleistung wird bewertet an Hand
- des Gesamtergebnis des Teams
- der Arbeitsleistung jeder/s Studierenden
an Hand folgender Kriterien:
- Projektergebnis
- wöchentlicher Projektfortschritt
- Mitarbeit im Team
Das Projektergebnis muss folgendes beinhalten:
- (Kurz)dokumentation aus der hervorgeht welche Leistung der jeweiligen Studierende erbrachten hat.
- Im Teilprojekt muss folgendes vorliegen:
- Eine Testsuite von JavaProgrammen, für die der Compilerteil funktioniert.
- Präsentation des Programms an Hand der erstellen Testsuites.
- Durchgehendes Beispiel, fur das der gesamte Compiler funktioniert.
- Abgabetermin: Letzte Semesterwoche
+5
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
public class Runner { public static void main(String[] args) { FieldsTest f = new FieldsTest(); System.out.println(f.b); } }
+279
View File
@@ -0,0 +1,279 @@
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
{ magic :: Magic,
minorVersion :: MinorVersion,
majorVersion :: MajorVersion,
constantPool :: CP_Infos,
accessFlags :: AccessFlags,
thisClass :: ThisClass,
superClass :: SuperClass,
interfaces :: Interfaces,
fields :: Field_Infos,
methods :: Method_Infos,
attributes :: Attribute_Infos
}
deriving (Show, Eq)
-- Counts are derivable from list lengths, so no need to store them separately
type Index = Int
type Interfaces = [Word16] -- constant pool indices
type Field_Infos = [Field_Info]
type Method_Infos = [Method_Info]
type Attribute_Infos = [Attribute_Info]
newtype Magic = Magic Word32 deriving (Show, Eq) -- always 0xCAFEBABE
newtype MinorVersion = MinorVersion Int deriving (Show, Eq)
newtype MajorVersion = MajorVersion Int deriving (Show, Eq) -- 52 = Java 8
newtype AccessFlags = AccessFlags [AccessFlag] deriving (Show, Eq)
newtype ThisClass = ThisClass Index deriving (Show, Eq)
newtype SuperClass = SuperClass Index deriving (Show, Eq)
data AccessFlag
= ACC_PUBLIC
| ACC_PRIVATE
| ACC_PROTECTED
| ACC_STATIC
| ACC_FINAL
| ACC_SUPER -- always set on classes
| ACC_INTERFACE
| ACC_ABSTRACT
| ACC_SYNTHETIC
| ACC_ENUM
deriving (Show, Eq)
data Field_Info = Field_Info
{ fieldAccessFlags :: AccessFlags,
fieldNameIndex :: Index,
fieldDescIndex :: Index,
fieldAttributes :: Attribute_Infos
}
deriving (Show, Eq)
data Method_Info = Method_Info
{ methodAccessFlags :: AccessFlags,
methodNameIndex :: Index,
methodDescIndex :: Index,
methodAttributes :: Attribute_Infos
}
deriving (Show, Eq)
data Attribute_Info
= Code_Attribute
{ codeNameIndex :: Index,
maxStack :: Int,
maxLocals :: Int,
codeBody :: [Word8], -- raw serialized bytecode
exceptionTable :: [ExceptionEntry],
codeAttributes :: Attribute_Infos
}
| Generic_Attribute
{ attrNameIndex :: Index,
attrData :: [Word8]
}
deriving (Show, Eq)
data ExceptionEntry = ExceptionEntry
{ startPc :: Int,
endPc :: Int,
handlerPc :: Int,
catchType :: Index -- 0 means catches all (finally)
}
deriving (Show, Eq)
generateClassFile :: TypedClass -> ClassFile
generateClassFile cls =
let constPool = makeConstpool cls
in ClassFile
{ magic = Magic 0xCAFEBABE,
minorVersion = MinorVersion 0,
majorVersion = MajorVersion 48,
constantPool = constPool,
accessFlags = makeAccessFlags,
thisClass = makeThisClass constPool cls,
superClass = makeSuperClass constPool,
interfaces = makeInterface,
fields = makeFields constPool cls,
methods = makeMethods constPool cls,
attributes = makeAttributes constPool
}
makeConstpool :: TypedClass -> CP_Infos
makeConstpool = generateConstPool
makeAccessFlags :: AccessFlags
makeAccessFlags = AccessFlags [ACC_PUBLIC, ACC_SUPER]
makeThisClass :: CP_Infos -> TypedClass -> ThisClass
makeThisClass constPool (Class name _ _) =
ThisClass (lookupClassIndex constPool name)
makeSuperClass :: CP_Infos -> SuperClass
makeSuperClass constPool =
SuperClass (lookupClassIndex constPool "java/lang/Object")
makeInterface :: Interfaces
makeInterface = []
makeFields :: CP_Infos -> TypedClass -> Field_Infos
makeFields constPool (Class _ fields _) = map (makeField constPool) fields
makeField :: CP_Infos -> TypedFieldDecl -> Field_Info
makeField constPool (Field fieldType name _) =
Field_Info
{ fieldAccessFlags = AccessFlags [ACC_PUBLIC],
fieldNameIndex = lookupUtf8Index constPool name,
fieldDescIndex = lookupUtf8Index constPool (typeDescriptor fieldType),
fieldAttributes = []
}
makeAttributes :: CP_Infos -> Attribute_Infos
makeAttributes _ = []
makeMethods :: CP_Infos -> TypedClass -> Method_Infos
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) =
Method_Info
{ methodAccessFlags = AccessFlags [ACC_PUBLIC],
methodNameIndex = lookupUtf8Index constPool name,
methodDescIndex = lookupUtf8Index constPool (methodDescriptor params returnType),
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
typeDescriptor :: Type -> String
typeDescriptor t = case t of
"int" -> "I"
"boolean" -> "Z"
"char" -> "C"
"void" -> "V"
_ -> "L" ++ t ++ ";"
+372
View File
@@ -0,0 +1,372 @@
module Codegen.ConstPool where
import Codegen.Types
import Data.List (isPrefixOf, isSuffixOf)
import qualified Grammar.TAST as TAST
------------------------------------------------------------------------
-- Recursive extraction of Tags from an already-built pool
------------------------------------------------------------------------
extractTags :: CP_Infos -> [Tag]
extractTags [] = []
extractTags (x : xs) = tag_cp x : extractTags xs
countEntries :: CP_Infos -> Int
countEntries [] = 0
countEntries (_ : xs) = 1 + countEntries xs
------------------------------------------------------------------------
-- Helper constructors
------------------------------------------------------------------------
mkClassInfo :: IndexConstantPool -> String -> CP_Info
mkClassInfo = ClassInfo TagClass
mkFieldRefInfo :: IndexConstantPool -> IndexConstantPool -> String -> CP_Info
mkFieldRefInfo = FieldRefInfo TagFieldRef
mkMethodRefInfo :: IndexConstantPool -> IndexConstantPool -> String -> CP_Info
mkMethodRefInfo = MethodRefInfo TagMethodRef
mkStringInfo :: IndexConstantPool -> String -> CP_Info
mkStringInfo = StringInfo TagString
mkIntegerInfo :: Int -> String -> CP_Info
mkIntegerInfo = IntegerInfo TagInteger
mkNameAndTypeInfo :: IndexConstantPool -> IndexConstantPool -> String -> CP_Info
mkNameAndTypeInfo = NameAndTypeInfo TagNameAndType
mkUtf8Info :: String -> String -> CP_Info
mkUtf8Info str = Utf8Info TagUtf8 (length str) str
------------------------------------------------------------------------
-- Tag utilities
------------------------------------------------------------------------
tagToByte :: Tag -> Int
tagToByte TagClass = 7
tagToByte TagFieldRef = 9
tagToByte TagMethodRef = 10
tagToByte TagString = 8
tagToByte TagInteger = 3
tagToByte TagNameAndType = 12
tagToByte TagUtf8 = 1
tagToString :: Tag -> String
tagToString TagClass = "Class"
tagToString TagFieldRef = "FieldRef"
tagToString TagMethodRef = "MethodRef"
tagToString TagString = "String"
tagToString TagInteger = "Integer"
tagToString TagNameAndType = "NameAndType"
tagToString TagUtf8 = "Utf8"
------------------------------------------------------------------------
-- Descriptor helpers
------------------------------------------------------------------------
typeToDescriptor :: String -> String
typeToDescriptor "int" = "I"
typeToDescriptor "boolean" = "Z"
typeToDescriptor "char" = "C"
typeToDescriptor "void" = "V"
typeToDescriptor t = "L" ++ t ++ ";"
methodDescriptor :: [(String, String)] -> String -> String
methodDescriptor params ret =
"(" ++ paramsDesc params ++ ")" ++ typeToDescriptor ret
where
paramsDesc [] = ""
paramsDesc ((pty, _) : ps) = typeToDescriptor pty ++ paramsDesc ps
------------------------------------------------------------------------
-- Recursive traversal of TAST to collect CP_Info entries
------------------------------------------------------------------------
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)]
collectFromTypedExpr (TAST.Bool _ _) =
[]
collectFromTypedExpr (TAST.Char c _) =
[mkIntegerInfo (fromEnum c) ("char " ++ show c)]
collectFromTypedExpr (TAST.Null _) =
[]
collectFromTypedExpr (TAST.This _) =
[]
collectFromTypedExpr (TAST.LocalOrFieldVar _ _) =
[]
collectFromTypedExpr (TAST.InstVar obj name typ) =
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 _) =
collectFromTypedExpr e1 ++ collectFromTypedExpr e2
collectFromTypedExpr (TAST.StmtExprExpr se _) =
collectFromTypedStmtExpr se
collectFromTypedStmtExpr :: TAST.TypedStmtExpr -> CP_Infos
collectFromTypedStmtExpr (TAST.Assign lhs rhs _) =
collectFromTypedExpr lhs ++ collectFromTypedExpr rhs
collectFromTypedStmtExpr (TAST.New t args _) =
collectFromExprs args
++ [ mkUtf8Info t ("class name: " ++ t),
mkClassInfo 0 ("class: " ++ t),
mkMethodRefInfo 0 0 ("new method ref: " ++ t ++ ".<init>:()V")
]
collectFromTypedStmtExpr (TAST.MethodCall obj name args retTyp) =
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 [] = []
collectFromStmts (s : ss) = collectFromTypedStmt s ++ collectFromStmts ss
collectFromTypedStmt :: TAST.TypedStmt -> CP_Infos
collectFromTypedStmt (TAST.Block stmts _) =
collectFromStmts stmts
collectFromTypedStmt (TAST.Return (Just e) _) =
collectFromTypedExpr e
collectFromTypedStmt (TAST.Return Nothing _) =
[]
collectFromTypedStmt (TAST.While cond body _) =
collectFromTypedExpr cond ++ collectFromTypedStmt body
collectFromTypedStmt (TAST.LocalVarDecl _ _ _) =
[]
collectFromTypedStmt (TAST.If cond then_ mElse _) =
collectFromTypedExpr cond
++ collectFromTypedStmt then_
++ collectFromMaybeStmt mElse
collectFromTypedStmt (TAST.StmtExprStmt se _) =
collectFromTypedStmtExpr se
collectFromTypedStmt (TAST.EmptyStmt _) =
[]
collectFromMaybeStmt :: Maybe TAST.TypedStmt -> CP_Infos
collectFromMaybeStmt Nothing = []
collectFromMaybeStmt (Just s) = collectFromTypedStmt s
collectFromFields :: [TAST.TypedFieldDecl] -> CP_Infos
collectFromFields [] = []
collectFromFields (TAST.Field fType fName _ : fs) =
[ mkUtf8Info fName ("field: " ++ fName),
mkUtf8Info (typeToDescriptor fType) ("field desc: " ++ fType)
]
++ collectFromFields fs
collectFromMethods :: [TAST.TypedMethodDecl] -> CP_Infos
collectFromMethods [] = []
collectFromMethods (TAST.Method mType mName params body : ms) =
[ mkUtf8Info mName ("method: " ++ mName),
mkUtf8Info (methodDescriptor params mType) ("method desc: " ++ mName)
]
++ collectFromTypedStmt body
++ collectFromMethods ms
------------------------------------------------------------------------
-- Build the complete constant pool for a class
------------------------------------------------------------------------
generateConstPool :: TAST.TypedClass -> CP_Infos
generateConstPool (TAST.Class cName fields 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 =
case findIndex matches pool of
Just i -> i
Nothing -> 0
where
matches entry = case entry of
ClassInfo {desc = descVal}
| name == "java/lang/Object" -> descVal == "super class" || isSuffixOf name descVal
| otherwise -> descVal == name || isSuffixOf name descVal
_ -> False
lookupUtf8Index :: CP_Infos -> String -> IndexConstantPool
lookupUtf8Index pool value =
case findIndex matches pool of
Just i -> i
Nothing -> 0
where
matches entry = case entry of
Utf8Info {cad_cp = cadVal, desc = descVal} -> cadVal == value || isSuffixOf value descVal
_ -> False
lookupNameAndTypeIndex :: CP_Infos -> String -> IndexConstantPool
lookupNameAndTypeIndex pool name =
case findIndex matches pool of
Just i -> i
Nothing -> lookupUtf8Index pool name
where
matches entry = case entry of
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
go _ [] = Nothing
go i (x : xs)
| predicate x = Just i
| otherwise = go (i + 1) xs
+171
View File
@@ -0,0 +1,171 @@
module Codegen.Lowerer where
import Codegen.ClassFile
import Codegen.Types (CP_Info (..), CP_Infos)
import Data.Word (Word8)
import Numeric (showHex)
data Instruction
= ALoad Int
| ALoad0
| ILoad Int
| AStore Int
| IStore Int
| GetField Int
| PutField Int
| InvokeSpecial Int
| 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
| AReturn
deriving (Show, Eq)
data BtcLine = BtcLine
{ lineNumber :: Integer,
instruction :: Instruction
}
deriving (Show, Eq)
newtype BtcProgram = BtcProgram [BtcLine]
deriving (Show, Eq)
-- Lower a full ClassFile into a BtcProgram per method
-- Returns one BtcProgram per method, paired with its name
lowerClassFile :: ClassFile -> [(String, BtcProgram)]
lowerClassFile cf =
[ (methodName cf m, lowerMethod m)
| m <- methods cf
]
-- Extract method name from the constant pool
methodName :: ClassFile -> Method_Info -> String
methodName cf m =
case lookupPool (constantPool cf) (methodNameIndex m) of
Just (Utf8Info {cad_cp = name}) -> name
_ -> "<unknown>"
-- Lower a single method's Code attribute into a BtcProgram
lowerMethod :: Method_Info -> BtcProgram
lowerMethod m =
case findCodeAttr (methodAttributes m) of
Just attr -> lowerCode attr
Nothing -> BtcProgram [] -- abstract/native method, no body
findCodeAttr :: Attribute_Infos -> Maybe Attribute_Info
findCodeAttr = foldr step Nothing
where
step attr@Code_Attribute {} _ = Just attr
step _ acc = acc
-- Reconstruct BtcProgram from raw code bytes
-- This is the tricky direction — bytes → instructions
lowerCode :: Attribute_Info -> BtcProgram
lowerCode attr = BtcProgram (decodeBytes 0 (codeBody attr))
decodeBytes :: Int -> [Word8] -> [BtcLine]
decodeBytes _ [] = []
decodeBytes pos (b : bs) = case b of
0x2A -> line ALoad0 pos 1 bs
0x2B -> line (ALoad 1) pos 1 bs
0x2C -> line (ALoad 2) pos 1 bs
0x2D -> line (ALoad 3) pos 1 bs
0x19 -> withByte bs pos $ \n rest -> line (ALoad n) pos 2 rest
0x1A -> line (ILoad 0) pos 1 bs
0x1B -> line (ILoad 1) pos 1 bs
0x1C -> line (ILoad 2) pos 1 bs
0x1D -> line (ILoad 3) pos 1 bs
0x15 -> withByte bs pos $ \n rest -> line (ILoad n) pos 2 rest
0x4B -> line (AStore 0) pos 1 bs
0x4C -> line (AStore 1) pos 1 bs
0x4D -> line (AStore 2) pos 1 bs
0x4E -> line (AStore 3) pos 1 bs
0x3A -> withByte bs pos $ \n rest -> line (AStore n) pos 2 rest
0x3B -> line (IStore 0) pos 1 bs
0x3C -> line (IStore 1) pos 1 bs
0x3D -> line (IStore 2) pos 1 bs
0x3E -> line (IStore 3) pos 1 bs
0x36 -> withByte bs pos $ \n rest -> line (IStore n) pos 2 rest
0xB4 -> withIndex bs pos $ \i rest -> line (GetField i) pos 3 rest
0xB5 -> withIndex bs pos $ \i rest -> line (PutField i) pos 3 rest
0xB7 -> withIndex bs pos $ \i rest -> line (InvokeSpecial i) pos 3 rest
0xB6 -> withIndex bs pos $ \i rest -> line (InvokeVirtual i) pos 3 rest
0xB8 -> withIndex bs pos $ \i rest -> line (InvokeStatic i) pos 3 rest
0x02 -> line (IConst (-1)) pos 1 bs
0x03 -> line (IConst 0) pos 1 bs
0x04 -> line (IConst 1) pos 1 bs
0x05 -> line (IConst 2) pos 1 bs
0x06 -> line (IConst 3) pos 1 bs
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
0xB0 -> line AReturn pos 1 bs
unknown -> error $ "Unknown opcode 0x" ++ showHex unknown "" ++ " at position " ++ show pos
-- Helpers
line :: Instruction -> Int -> Int -> [Word8] -> [BtcLine]
line instr pos size rest = BtcLine (toInteger pos) instr : decodeBytes (pos + size) rest
withByte :: [Word8] -> Int -> (Int -> [Word8] -> [BtcLine]) -> [BtcLine]
withByte (b : rest) _ f = f (fromIntegral b) rest
withByte [] pos _ = error $ "Unexpected end of bytecode at " ++ show pos
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
+164
View File
@@ -0,0 +1,164 @@
module Codegen.Serializer where
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]
indexBytes n =
[ fromIntegral (n `shiftR` 8 .&. 0xFF),
fromIntegral (n .&. 0xFF)
]
serializeInstruction :: Instruction -> [Word8]
serializeInstruction instr = case instr of
-- aload_<n>: 0x2A0x2D for 03, else wide form 0x19 <index>
ALoad 0 -> [0x2A]
ALoad 1 -> [0x2B]
ALoad 2 -> [0x2C]
ALoad 3 -> [0x2D]
ALoad n -> [0x19, fromIntegral n]
ALoad0 -> [0x2A] -- shorthand for ALoad 0
-- iload_<n>: 0x1A0x1D for 03, else wide form 0x15 <index>
ILoad 0 -> [0x1A]
ILoad 1 -> [0x1B]
ILoad 2 -> [0x1C]
ILoad 3 -> [0x1D]
ILoad n -> [0x15, fromIntegral n]
-- astore_<n>: 0x4B0x4E for 03, else 0x3A <index>
AStore 0 -> [0x4B]
AStore 1 -> [0x4C]
AStore 2 -> [0x4D]
AStore 3 -> [0x4E]
AStore n -> [0x3A, fromIntegral n]
-- istore_<n>: 0x3B0x3E for 03, else 0x36 <index>
IStore 0 -> [0x3B]
IStore 1 -> [0x3C]
IStore 2 -> [0x3D]
IStore 3 -> [0x3E]
IStore n -> [0x36, fromIntegral n]
-- Field access: opcode + 2-byte constant pool index
GetField i -> 0xB4 : indexBytes i
PutField i -> 0xB5 : indexBytes i
-- Method invocation: opcode + 2-byte constant pool index
InvokeSpecial i -> 0xB7 : indexBytes i
InvokeVirtual i -> 0xB6 : indexBytes i
InvokeStatic i -> 0xB8 : indexBytes i
-- iconst_<n>: -1 through 5 have dedicated opcodes
IConst (-1) -> [0x02]
IConst 0 -> [0x03]
IConst 1 -> [0x04]
IConst 2 -> [0x05]
IConst 3 -> [0x06]
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
| i <= 255 -> [0x12, fromIntegral i]
| otherwise -> 0x13 : indexBytes i -- ldc_w
-- Arithmetic
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]
IReturn -> [0xAC]
AReturn -> [0xB0]
-- Serialize a full program — concatenate all instruction bytes
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)
+57
View File
@@ -0,0 +1,57 @@
module Codegen.Types where
type IndexConstantPool = Int
type CP_Infos = [CP_Info]
data CP_Info
= ClassInfo
{ tag_cp :: Tag,
index_cp :: IndexConstantPool,
desc :: String
}
| FieldRefInfo
{ tag_cp :: Tag,
index_name_cp :: IndexConstantPool,
index_nameandtype_cp :: IndexConstantPool,
desc :: String
}
| MethodRefInfo
{ tag_cp :: Tag,
index_name_cp :: IndexConstantPool,
index_nameandtype_cp :: IndexConstantPool,
desc :: String
}
| StringInfo
{ tag_cp :: Tag,
index_cp :: IndexConstantPool,
desc :: String
}
| IntegerInfo
{ tag_cp :: Tag,
numi_cp :: Int,
desc :: String
}
| NameAndTypeInfo
{ tag_cp :: Tag,
index_name_cp :: IndexConstantPool,
index_descr_cp :: IndexConstantPool,
desc :: String
}
| Utf8Info
{ tag_cp :: Tag,
tam_cp :: Int,
cad_cp :: String,
desc :: String
}
deriving (Eq, Show)
data Tag
= TagClass
| TagFieldRef
| TagMethodRef
| TagString
| TagInteger
| TagNameAndType
| TagUtf8
deriving (Eq, Ord, Show)
+4 -3
View File
@@ -6,7 +6,7 @@ type Program = [Class]
data Class = Class Type [FieldDecl] [MethodDecl] deriving (Show, Eq)
data FieldDecl = Field Type String deriving (Show, Eq)
data FieldDecl = Field Type String (Maybe Expr) deriving (Show, Eq)
data MethodDecl = Method Type String [(Type, String)] Stmt deriving (Show, Eq)
@@ -19,7 +19,7 @@ data Expr
| Integer Integer
| Bool Bool
| Char Char
| Jnull
| Null
| StmtExprExpr StmtExpr
deriving (Show, Eq)
@@ -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
+41 -11
View File
@@ -10,14 +10,18 @@ import Grammar.AST
%error { parseError }
%token
public { TokenVisibility Public }
private { TokenVisibility Private }
class { TokenClass }
void { TokenVoid }
return { TokenReturn }
new { TokenNew }
this { TokenThis }
null { TokenNull }
if { TokenIf }
else { TokenElse }
while { TokenWhile }
for { TokenFor }
int { TokenIntType }
boolean { TokenBoolType }
char { TokenCharType }
@@ -68,15 +72,29 @@ Classes : Classes ClassDecl { $2 : $1 }
| ClassDecl { [$1] }
ClassDecl : class id '{' Decls '}' { Class $2 (fst $4) (snd $4) }
| public class id '{' Decls '}' { Class $3 (fst $5) (snd $5) }
| private class id '{' Decls '}' { Class $3 (fst $5) (snd $5) }
Decls : FieldDecl Decls { ($1 : fst $2, snd $2) }
| MethodDecl Decls { (fst $2, $1 : snd $2) }
| {- leer -} { ([], []) }
FieldDecl : Type id ';' { Field $1 $2 }
FieldDecl : Type id ';' { Field $1 $2 Nothing }
| public Type id ';' { Field $2 $3 Nothing }
| private Type id ';' { Field $2 $3 Nothing }
| Type id '=' Expr ';' { Field $1 $2 (Just $4) }
| public Type id '=' Expr ';' { Field $2 $3 (Just $5) }
| private Type id '=' Expr ';' { Field $2 $3 (Just $5) }
MethodDecl : Type id '(' Params ')' Block { Method $1 $2 $4 $6 }
| void id '(' Params ')' Block { Method "void" $2 $4 $6 }
MethodDecl : Type id '(' Params ')' Block { Method $1 $2 $4 $6 }
| public Type id '(' Params ')' Block { Method $2 $3 $5 $7 }
| private Type id '(' Params ')' Block { Method $2 $3 $5 $7 }
| 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 -} { [] }
@@ -96,18 +114,29 @@ Block : '{' Stmts '}' { Block (reverse $2) }
Stmts : Stmts Stmt { $2 : $1 }
| {- leer -} { [] }
Stmt : Block { $1 }
| return Expr ';' { Return $2 }
| 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 }
@@ -115,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 }
@@ -141,5 +171,5 @@ ExprList : Expr { [$1] }
{
parseError :: [Token] -> a
parseError tokens = error $ "Lexical error or syntax error at: " ++ show tokens
parseError tokens = error $ "abc Lexical error or syntax error at: " ++ show tokens
}
+11 -1
View File
@@ -14,11 +14,14 @@ tokens :-
"/*"([^\*]|(\*+([^\*\/])))*\*+\/ ; -- multi-line comments
-- key words
public { \_ -> TokenVisibility Public }
private { \_ -> TokenVisibility Private }
class { \_ -> TokenClass }
void { \_ -> TokenVoid }
return { \_ -> TokenReturn }
new { \_ -> TokenNew }
this { \_ -> TokenThis }
null { \_ -> TokenNull }
if { \_ -> TokenIf }
else { \_ -> TokenElse }
while { \_ -> TokenWhile }
@@ -49,13 +52,20 @@ tokens :-
$alpha [$alpha $digit]* { \s -> TokenIdent s }
{
data Visibility
= Public
| Private
deriving (Eq, Show)
data Token
= TokenClass
= TokenVisibility Visibility
| TokenClass
| TokenStatic
| TokenVoid
| TokenReturn
| TokenNew
| TokenThis
| TokenNull
| TokenIf
| TokenElse
| TokenWhile
+31 -6
View File
@@ -1,13 +1,38 @@
module Grammar.TAST where
import Grammar.AST
import Grammar.AST (BinaryOperator, Type, UnaryOperator)
data TypedExpr = TypedExpr Expr Type
data TypedClass = Class Type [TypedFieldDecl] [TypedMethodDecl] deriving (Show, Eq)
data TypedStmtExpr = TypedStmtExpr StmtExpr Type
data TypedFieldDecl = Field Type String (Maybe TypedExpr) deriving (Show, Eq)
data TypedStmt = TypedStmt Stmt Type
data TypedMethodDecl = Method Type String [(Type, String)] TypedStmt deriving (Show, Eq)
data TypedBinaryOperator = TypedBinaryOperator BinaryOperator Type
data TypedExpr
= This Type
| LocalOrFieldVar String Type
| InstVar TypedExpr String Type
| Unary UnaryOperator TypedExpr Type
| Binary BinaryOperator TypedExpr TypedExpr Type
| Integer Integer Type
| Bool Bool Type
| Char Char Type
| Null Type
| StmtExprExpr TypedStmtExpr Type
deriving (Show, Eq)
data TypedUnaryOperator = TypedUnaryOperator UnaryOperator Type
data TypedStmtExpr
= Assign TypedExpr TypedExpr Type
| New Type [TypedExpr] Type
| MethodCall TypedExpr String [TypedExpr] Type
deriving (Show, Eq)
data TypedStmt
= Block [TypedStmt] Type
| Return (Maybe TypedExpr) Type
| While TypedExpr TypedStmt Type
| LocalVarDecl Type String Type
| If TypedExpr TypedStmt (Maybe TypedStmt) Type
| StmtExprStmt TypedStmtExpr Type
| EmptyStmt Type
deriving (Show, Eq)
+49 -5
View File
@@ -1,10 +1,54 @@
module Main where
import Grammar.AST
import Grammar.TAST
import Typecheck.SemanticChecker
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)
import Grammar.TAST (TypedClass (Class))
import System.Environment (getArgs)
import Typecheck.SemanticChecker (typeCheckClass)
main :: IO ()
main = do
let t = getTypeFromExpr $ TypedExpr This "myType"
putStrLn t
args <- getArgs
case args of
[path] -> runPipeline path
_ -> putStrLn "Usage: compoiler <input.java>"
runPipeline :: FilePath -> IO ()
runPipeline path = do
source <- readFile path
let tokens = scan source
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
parseProgram :: [Token] -> Program
parseProgram = parse
typeCheckProgram :: Program -> [TypedClass]
typeCheckProgram classes =
map (\cls -> typeCheckClass cls [] classes) classes
reportSuccess :: Program -> [TypedClass] -> [ClassFile] -> IO ()
reportSuccess ast typed classFiles = do
putStrLn ("Parsed classes: " ++ show (length ast))
putStrLn ("Typed classes: " ++ show (length typed))
putStrLn ("Generated class files: " ++ show (length classFiles))
putStrLn ("Class names: " ++ unwords (map className typed))
className :: TypedClass -> String
className (Class name _ _) = name
@@ -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}
]
)
]
+15
View File
@@ -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}
]
)
]
+18
View File
@@ -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}
]
)
]
+49
View File
@@ -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}
]
)
]
+52
View File
@@ -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}
]
)
]
+21
View File
@@ -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}
]
)
]
+40
View File
@@ -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,48 @@
module Testsuite.AstFiles.ArithmeticTestAST (expectedAST) where
import Grammar.AST
expectedAST =
[ Class
"ArithmeticTest"
[]
[ Method
"int"
"basic"
[("int", "a"), ("int", "b"), ("int", "c")]
( Block
[ Return
( Just
( Binary
Subtract
(Binary Add (LocalOrFieldVar "a") (LocalOrFieldVar "b"))
( Binary
Modulo
( Binary
Divide
(Binary Multiply (LocalOrFieldVar "c") (LocalOrFieldVar "a"))
(LocalOrFieldVar "b")
)
(LocalOrFieldVar "c")
)
)
)
]
),
Method
"boolean"
"logic"
[("boolean", "a"), ("boolean", "b"), ("boolean", "c")]
( Block
[ Return
( Just
( Binary
And
(Unary Not (LocalOrFieldVar "a"))
(Binary Or (LocalOrFieldVar "c") (LocalOrFieldVar "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"))])
]
]
+10
View File
@@ -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"))
]
)
]
]
+12
View File
@@ -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))
]
[]
]
+27
View File
@@ -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)))]))
)
)
]
)
]
]
+50
View File
@@ -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)])
]
)
)
)
]
)
]
]
+15
View File
@@ -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"))
]
)
]
]
+34
View File
@@ -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"))
]
)
]
]
@@ -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
+79
View File
@@ -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)
]
+337
View File
@@ -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)
+16
View File
@@ -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])]
}
+15
View File
@@ -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")
]
]
+10
View File
@@ -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"
)
]
]
+13
View File
@@ -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"))
]
[]
]
+60
View File
@@ -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"
)
]
]
+78
View File
@@ -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"
)
]
]
+19
View File
@@ -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"
)
]
]
+43
View File
@@ -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"
)
]
]
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.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More