added memory allocator with tests
This commit is contained in:
		
							parent
							
								
									b617136564
								
							
						
					
					
						commit
						87b859a70c
					
				| 
						 | 
				
			
			@ -167,7 +167,8 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitExpr(ExprContext ctx) {
 | 
			
		||||
		if (ctx.singleExpr(ctx.singleExpr().size() - 1) instanceof DeclareContext)
 | 
			
		||||
		ParserRuleContext lastExpr = ctx.singleExpr(ctx.singleExpr().size() - 1);
 | 
			
		||||
		if (lastExpr instanceof DeclareContext || lastExpr instanceof DeclareFunctionContext)
 | 
			
		||||
			log.severe(getError(ctx, "Compound expression ends with declaration."));
 | 
			
		||||
 | 
			
		||||
		return ctx.singleExpr().stream().map(this::visit).reduce((__, snd) -> snd).get();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,162 @@
 | 
			
		|||
fst_ptr <- 28
 | 
			
		||||
slot1 <- 32
 | 
			
		||||
header <- 8
 | 
			
		||||
off_oref <- -8
 | 
			
		||||
off_osize <- -4
 | 
			
		||||
off_next <- 0
 | 
			
		||||
off_size <- 4
 | 
			
		||||
 | 
			
		||||
// memlib - simple memory allocator for ILOC
 | 
			
		||||
//
 | 
			
		||||
// This library maintains a single-linked list (of monotonically increasing addresses) of free
 | 
			
		||||
// slots in memory and a reference count for occupied slots. Each slot contains a tuple `(next
 | 
			
		||||
// free slot address,size)` followed by `size` free bytes. The memory is initiliased with a
 | 
			
		||||
// pointer to the first free slot at `#fst_ptr` and one free slot at `#slot1` of size
 | 
			
		||||
// `brk-slot1-header`. When a piece of memory is requested for allocation, a tuple
 | 
			
		||||
// `(reference count, size)` followed by `size` bytes for the object is formed. The calling
 | 
			
		||||
// convention of the functions in this library consists of storing the return address at #0,
 | 
			
		||||
// arguments at #4, #8 and #12 and return values (if any) at #16, #20 and #24.
 | 
			
		||||
//
 | 
			
		||||
// Requires a register `brk` for the highest address available for heap allocation.
 | 
			
		||||
// Requires an instruction `halt` when memory runs out
 | 
			
		||||
//
 | 
			
		||||
// @author Frank Wibbelink
 | 
			
		||||
 | 
			
		||||
// initialise
 | 
			
		||||
memlib_: loadI    0 => m_0
 | 
			
		||||
         loadI    @slot1 => m_1
 | 
			
		||||
         subI     brk,@slot1 => m_2
 | 
			
		||||
         subI     m_2,@header => m_2
 | 
			
		||||
         storeAI  m_1 => m_0,@fst_ptr            // pointer to first slot
 | 
			
		||||
         storeAI  m_0 => m_1,@off_next           // next slot is null
 | 
			
		||||
         storeAI  m_2 => m_1,@off_size           // first slot size
 | 
			
		||||
         jumpI -> ememlib_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// allocate memory
 | 
			
		||||
// searches through the free slots for either a slot size of ~~exactly #4+8 or a size of~~ at
 | 
			
		||||
// least #4+16
 | 
			
		||||
// memory: [return address, object size] -> [object address]
 | 
			
		||||
memalloc: loadI    0 => m_0
 | 
			
		||||
          loadAI   m_0,4 => m_s                  // load size from #4
 | 
			
		||||
          loadI    @fst_ptr => m_p               // load previous address (base pointer)
 | 
			
		||||
          loadAI   m_p,@off_next => m_c          // load current address (first slot)
 | 
			
		||||
 | 
			
		||||
ma_loop:  cmp_EQ   m_0,m_c => m_1                // check if address pointer is null
 | 
			
		||||
          cbr      m_1 -> ma_null,ma_cont        // if null, go to end and return null pointer
 | 
			
		||||
ma_cont:  loadAI   m_c,@off_size => m_1          // load slot size
 | 
			
		||||
          cmp_EQ   m_1,m_s => m_2                // check if request fits exactly
 | 
			
		||||
          cbr      m_2 -> ma_yxct,ma_nxct
 | 
			
		||||
ma_nxct:  subI     m_1,@header => m_1            // subtract free slot size
 | 
			
		||||
          cmp_GE   m_1,m_s => m_1                // check if request fits
 | 
			
		||||
          cbr      m_1 -> ma_found,ma_next
 | 
			
		||||
ma_next:  i2i      m_c => m_p
 | 
			
		||||
          loadAI   m_p,@off_next => m_c
 | 
			
		||||
          jumpI -> ma_loop
 | 
			
		||||
 | 
			
		||||
ma_yxct:  loadAI   m_c,@off_next => m_n          // location of next free slot
 | 
			
		||||
          jumpI -> ma_final
 | 
			
		||||
 | 
			
		||||
ma_found: addI     m_s,@header => m_1
 | 
			
		||||
          add      m_1,m_c => m_n                // location of new free slot
 | 
			
		||||
          loadAI   m_c,@off_size => m_1
 | 
			
		||||
          subI     m_1,@header => m_1
 | 
			
		||||
          sub      m_1,m_s => m_1                // size of new free slot
 | 
			
		||||
          storeAI  m_1 => m_n,@off_size
 | 
			
		||||
          loadAI   m_c,@off_next => m_1          // location of next free slot
 | 
			
		||||
          storeAI  m_1 => m_n,@off_next
 | 
			
		||||
ma_final: storeAI  m_n => m_p,@off_next          // link previous free slot to new
 | 
			
		||||
          addI     m_c,@header => m_c            // move to object location
 | 
			
		||||
          loadI    1 => m_1
 | 
			
		||||
          storeAI  m_1 => m_c,@off_oref          // set reference count to 1
 | 
			
		||||
          storeAI  m_s => m_c,@off_osize         // set object size
 | 
			
		||||
ma_null:  storeAI  m_c => m_0,16                 // store object address at #16
 | 
			
		||||
          loadAI   m_0,0 => m_r                  // load return address from #0
 | 
			
		||||
          jump -> m_r
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// increase reference count of object
 | 
			
		||||
// memory: [return address, object address] -> []
 | 
			
		||||
memaddref: loadI    0 => m_0
 | 
			
		||||
           loadAI   m_0,4 => m_n                 // load object address from #4
 | 
			
		||||
           cmp_EQ   m_0,m_n => m_1
 | 
			
		||||
           cbr      m_1 -> mr_ynul,mr_nnul       // check if null pointer
 | 
			
		||||
mr_ynul:   haltI    1865445997
 | 
			
		||||
mr_nnul:   loadAI   m_n,@off_oref => m_1
 | 
			
		||||
           addI     m_1,1 => m_1
 | 
			
		||||
           storeAI  m_1 => m_n,@off_oref
 | 
			
		||||
           loadAI   m_0,0 => m_r                 // load return address from #0
 | 
			
		||||
           jump -> m_r
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// decrease reference count of object
 | 
			
		||||
// frees memory if count goes to zero
 | 
			
		||||
// memory: [return address, object address] -> []
 | 
			
		||||
memfree: loadI    0 => m_0
 | 
			
		||||
         loadAI   m_0,4 => m_n                   // load object from #4
 | 
			
		||||
         cmp_EQ   m_0,m_n => m_1
 | 
			
		||||
         cbr      m_1 -> mf_ynul,mf_nnul         // check if null pointer
 | 
			
		||||
mf_ynul: haltI    1865442925
 | 
			
		||||
mf_nnul: loadAI   m_n,@off_oref => m_1
 | 
			
		||||
         subI     m_1,1 => m_1
 | 
			
		||||
         cmp_GT   m_1,m_0 => m_1
 | 
			
		||||
         cbr      m_1 -> mf_exit,mf_free
 | 
			
		||||
 | 
			
		||||
mf_exit: storeAI  m_1 => m_n,@off_oref
 | 
			
		||||
         loadAI   m_0,0 => m_r                   // load return address from #0
 | 
			
		||||
         jump -> m_r
 | 
			
		||||
 | 
			
		||||
mf_free: subI     m_n,@header => m_n
 | 
			
		||||
         loadI    @fst_ptr => m_p
 | 
			
		||||
         loadAI   m_p,@off_next => m_c
 | 
			
		||||
 | 
			
		||||
mf_loop: cmp_EQ   m_0,m_c => m_1                 // check if address pointer is null
 | 
			
		||||
         cbr      m_1 -> mf_halt,mf_cont
 | 
			
		||||
mf_halt: haltI    1882220141                     // halt program; object beyond last free slot (or memory corrupted)
 | 
			
		||||
mf_cont: cmp_EQ   m_c,m_n => m_1
 | 
			
		||||
         cbr      m_1 -> mf_hal2,mf_con2
 | 
			
		||||
mf_hal2: haltI    1717855853                     // halt program; object is free slot
 | 
			
		||||
mf_con2: cmp_LE   m_c,m_n => m_1
 | 
			
		||||
         cbr      m_1 -> mf_next, mf_done
 | 
			
		||||
mf_next: i2i      m_c => m_p
 | 
			
		||||
         loadAI   m_p,@off_next => m_c
 | 
			
		||||
         jumpI -> mf_loop
 | 
			
		||||
 | 
			
		||||
mf_done: loadAI   m_p,@off_size => m_1
 | 
			
		||||
         addI     m_1,@header => m_1
 | 
			
		||||
         add      m_1,m_p => m_2
 | 
			
		||||
         cmp_EQ   m_2,m_n => m_2
 | 
			
		||||
         cbr      m_2 -> mf_yprv,mf_nprv
 | 
			
		||||
mf_yprv: loadAI   m_n,@off_size => m_2           // merge with previous free slot
 | 
			
		||||
         add      m_1,m_2 => m_1                 // new size of previous free slot
 | 
			
		||||
         storeAI  m_1 => m_p,@off_size
 | 
			
		||||
         i2i      m_p => m_n
 | 
			
		||||
         jumpI -> mf_dprv
 | 
			
		||||
mf_nprv: storeAI  m_n => m_p,@off_next           // link previous free slot with new
 | 
			
		||||
mf_dprv: loadAI   m_n,@off_size => m_1
 | 
			
		||||
         addI     m_1,@header => m_1
 | 
			
		||||
         add      m_1,m_n => m_2
 | 
			
		||||
         cmp_EQ   m_2,m_c => m_2
 | 
			
		||||
         cbr      m_2 -> mf_ynxt,mf_nnxt
 | 
			
		||||
mf_ynxt: loadAI   m_c,@off_size => m_2           // merge with next free slot
 | 
			
		||||
         add      m_1,m_2 => m_1                 // new size of next free slot
 | 
			
		||||
         storeAI  m_1 => m_n,@off_size
 | 
			
		||||
         loadAI   m_c,@off_next => m_1
 | 
			
		||||
         storeAI  m_1 => m_n,@off_next           // move link of next's next to new free slot
 | 
			
		||||
         jumpI -> mf_exit
 | 
			
		||||
mf_nnxt: storeAI  m_c => m_n,@off_next           // link new free slot with next
 | 
			
		||||
         loadAI   m_0,0 => m_r                   // load return address from #0
 | 
			
		||||
         jump -> m_r
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// copy object to location
 | 
			
		||||
// memory: [return address, object address, destination] -> []
 | 
			
		||||
memcopy: loadI    0 => m_0
 | 
			
		||||
         haltI    1835626101                     // unimplemented
 | 
			
		||||
         loadAI   m_0,0 => m_r                   // load return address from #0
 | 
			
		||||
         jump -> m_r
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ememlib_: nop
 | 
			
		||||
// end of memlib
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,191 +1,16 @@
 | 
			
		|||
package pp.s1184725.boppi.test;
 | 
			
		||||
 | 
			
		||||
import java.nio.file.*;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import org.antlr.v4.runtime.CharStream;
 | 
			
		||||
import org.antlr.v4.runtime.tree.ParseTree;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
import org.junit.runners.Suite.SuiteClasses;
 | 
			
		||||
 | 
			
		||||
import pp.iloc.Simulator;
 | 
			
		||||
import pp.iloc.model.Program;
 | 
			
		||||
import pp.s1184725.boppi.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test suite for all Boppi language features. This suite contains helper
 | 
			
		||||
 * functions and attributes to assist test cases. Each test case should consider
 | 
			
		||||
 * a single language feature across all compiler stages.
 | 
			
		||||
 * Test suite for all tests, including the Boppi language and utilities.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Frank Wibbelink
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(Suite.class)
 | 
			
		||||
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class })
 | 
			
		||||
@SuiteClasses({ BoppiTests.class, ILOCAllocatorTest.class })
 | 
			
		||||
public class AllTests {
 | 
			
		||||
	/**
 | 
			
		||||
	 * The path for test programs
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Path TEST_PROGRAM_LOCATION = Paths
 | 
			
		||||
			.get("src/" + AllTests.class.getPackage().getName().replaceAll("\\.", "/") + "/programs/");
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The default logging level
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Level DEFAULT_LOG_LEVEL = Level.SEVERE;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Log records of last test
 | 
			
		||||
	 */
 | 
			
		||||
	public static List<LogRecord> log;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Output of last program split by line breaks
 | 
			
		||||
	 */
 | 
			
		||||
	public static String[] out;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The level of error reporting to use for the tests. Can be changed to
 | 
			
		||||
	 * include finer tests.
 | 
			
		||||
	 */
 | 
			
		||||
	private static Level logLevel = DEFAULT_LOG_LEVEL;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Runs a test with warnings enabled.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param test
 | 
			
		||||
	 *            the test to run
 | 
			
		||||
	 */
 | 
			
		||||
	public static void withWarnings(Runnable test) {
 | 
			
		||||
		logLevel = Level.WARNING;
 | 
			
		||||
		test.run();
 | 
			
		||||
		logLevel = DEFAULT_LOG_LEVEL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses a string of code, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to parse
 | 
			
		||||
	 */
 | 
			
		||||
	public static void parseString(String code) {
 | 
			
		||||
		parse(ToolChain.getCharStream(code));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses code from a file, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 */
 | 
			
		||||
	public static void parseFile(String file) {
 | 
			
		||||
		parse(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void parse(CharStream stream) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses and type checks a string of code, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to type check
 | 
			
		||||
	 */
 | 
			
		||||
	public static void checkString(String code) {
 | 
			
		||||
		check(ToolChain.getCharStream(code));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses and type checks code from a file, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 */
 | 
			
		||||
	public static void checkFile(String file) {
 | 
			
		||||
		check(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void check(CharStream stream) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ToolChain.getAnnotations(ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(), logger);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program from a string, logging to {@link #log} and
 | 
			
		||||
	 * writing lines of output to {@link #out}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to type check
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void compileAndRunString(String code, String... input) {
 | 
			
		||||
		compileAndRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program from a file, logging to {@link #log} and
 | 
			
		||||
	 * writing lines of output to {@link #out}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void compileAndRunFile(String file, String... input) {
 | 
			
		||||
		compileAndRun(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)), String.join("\n", input) + "\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void compileAndRun(CharStream stream, String input) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
		Annotations annotations = ToolChain.getAnnotations(ast, logger);
 | 
			
		||||
		Program program = ToolChain.getILOC(ast, logger, annotations);
 | 
			
		||||
 | 
			
		||||
		if (Simulator.DEBUG)
 | 
			
		||||
			System.out.println(program.prettyPrint());
 | 
			
		||||
 | 
			
		||||
		out = ToolChain.execute(program, logger, input).split("\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program in debug mode, printing the generated
 | 
			
		||||
	 * program, a simulation of the program and all log messages.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param stream
 | 
			
		||||
	 *            a character stream with the program code
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void debugRun(CharStream stream, String... input) {
 | 
			
		||||
		Simulator.DEBUG = true;
 | 
			
		||||
		String in = String.join("\n", input) + "\n";
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(Level.FINEST);
 | 
			
		||||
 | 
			
		||||
		ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
		Annotations annotations = ToolChain.getAnnotations(ast, logger);
 | 
			
		||||
		Program program = ToolChain.getILOC(ast, logger, annotations);
 | 
			
		||||
 | 
			
		||||
		System.out.println(program.prettyPrint());
 | 
			
		||||
 | 
			
		||||
		out = ToolChain.execute(program, logger, in).split("\n");
 | 
			
		||||
 | 
			
		||||
		log.forEach((entry) -> System.out.println(entry.getMessage()));
 | 
			
		||||
		Simulator.DEBUG = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
package pp.s1184725.boppi.test;
 | 
			
		||||
 | 
			
		||||
import java.nio.file.*;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.*;
 | 
			
		||||
 | 
			
		||||
import org.antlr.v4.runtime.CharStream;
 | 
			
		||||
import org.antlr.v4.runtime.tree.ParseTree;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
import org.junit.runners.Suite.SuiteClasses;
 | 
			
		||||
 | 
			
		||||
import pp.iloc.Simulator;
 | 
			
		||||
import pp.iloc.model.Program;
 | 
			
		||||
import pp.s1184725.boppi.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Test suite for all Boppi language features. This suite contains helper
 | 
			
		||||
 * functions and attributes to assist test cases. Each test case should consider
 | 
			
		||||
 * a single language feature across all compiler stages.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Frank Wibbelink
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(Suite.class)
 | 
			
		||||
@SuiteClasses({ ExpressionTest.class, SimpleVariableTest.class, ConditionalTest.class, SimpleFunctionTest.class })
 | 
			
		||||
public class BoppiTests {
 | 
			
		||||
	/**
 | 
			
		||||
	 * The path for test programs
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Path TEST_PROGRAM_LOCATION = Paths
 | 
			
		||||
			.get("src/" + BoppiTests.class.getPackage().getName().replaceAll("\\.", "/") + "/programs/");
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The default logging level
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Level DEFAULT_LOG_LEVEL = Level.SEVERE;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Log records of last test
 | 
			
		||||
	 */
 | 
			
		||||
	public static List<LogRecord> log;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Output of last program split by line breaks
 | 
			
		||||
	 */
 | 
			
		||||
	public static String[] out;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The level of error reporting to use for the tests. Can be changed to
 | 
			
		||||
	 * include finer tests.
 | 
			
		||||
	 */
 | 
			
		||||
	private static Level logLevel = DEFAULT_LOG_LEVEL;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Runs a test with warnings enabled.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param test
 | 
			
		||||
	 *            the test to run
 | 
			
		||||
	 */
 | 
			
		||||
	public static void withWarnings(Runnable test) {
 | 
			
		||||
		logLevel = Level.WARNING;
 | 
			
		||||
		test.run();
 | 
			
		||||
		logLevel = DEFAULT_LOG_LEVEL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses a string of code, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to parse
 | 
			
		||||
	 */
 | 
			
		||||
	public static void parseString(String code) {
 | 
			
		||||
		parse(ToolChain.getCharStream(code));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses code from a file, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 */
 | 
			
		||||
	public static void parseFile(String file) {
 | 
			
		||||
		parse(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void parse(CharStream stream) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses and type checks a string of code, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to type check
 | 
			
		||||
	 */
 | 
			
		||||
	public static void checkString(String code) {
 | 
			
		||||
		check(ToolChain.getCharStream(code));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Parses and type checks code from a file, logging to {@link #log}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 */
 | 
			
		||||
	public static void checkFile(String file) {
 | 
			
		||||
		check(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void check(CharStream stream) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ToolChain.getAnnotations(ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program(), logger);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program from a string, logging to {@link #log} and
 | 
			
		||||
	 * writing lines of output to {@link #out}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param code
 | 
			
		||||
	 *            the code to type check
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void compileAndRunString(String code, String... input) {
 | 
			
		||||
		compileAndRun(ToolChain.getCharStream(code), String.join("\n", input) + "\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program from a file, logging to {@link #log} and
 | 
			
		||||
	 * writing lines of output to {@link #out}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param file
 | 
			
		||||
	 *            the file name
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void compileAndRunFile(String file, String... input) {
 | 
			
		||||
		compileAndRun(ToolChain.getCharStream(TEST_PROGRAM_LOCATION.resolve(file)), String.join("\n", input) + "\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static void compileAndRun(CharStream stream, String input) {
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(logLevel);
 | 
			
		||||
 | 
			
		||||
		ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
		Annotations annotations = ToolChain.getAnnotations(ast, logger);
 | 
			
		||||
		Program program = ToolChain.getILOC(ast, logger, annotations);
 | 
			
		||||
 | 
			
		||||
		if (Simulator.DEBUG)
 | 
			
		||||
			System.out.println(program.prettyPrint());
 | 
			
		||||
 | 
			
		||||
		out = ToolChain.execute(program, logger, input).split("\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Compiles and runs a program in debug mode, printing the generated
 | 
			
		||||
	 * program, a simulation of the program and all log messages.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param stream
 | 
			
		||||
	 *            a character stream with the program code
 | 
			
		||||
	 * @param input
 | 
			
		||||
	 *            lines of input for the program
 | 
			
		||||
	 */
 | 
			
		||||
	public static void debugRun(CharStream stream, String... input) {
 | 
			
		||||
		Simulator.DEBUG = true;
 | 
			
		||||
		String in = String.join("\n", input) + "\n";
 | 
			
		||||
		Logger logger = Logger.getAnonymousLogger();
 | 
			
		||||
		log = ToolChain.makeListLog(logger);
 | 
			
		||||
		logger.setLevel(Level.FINEST);
 | 
			
		||||
 | 
			
		||||
		ParseTree ast = ToolChain.getParser(ToolChain.getLexer(stream, logger), logger).program();
 | 
			
		||||
		Annotations annotations = ToolChain.getAnnotations(ast, logger);
 | 
			
		||||
		Program program = ToolChain.getILOC(ast, logger, annotations);
 | 
			
		||||
 | 
			
		||||
		System.out.println(program.prettyPrint());
 | 
			
		||||
 | 
			
		||||
		out = ToolChain.execute(program, logger, in).split("\n");
 | 
			
		||||
 | 
			
		||||
		log.forEach((entry) -> System.out.println(entry.getMessage()));
 | 
			
		||||
		Simulator.DEBUG = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,11 +16,11 @@ public class ConditionalTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctConditionalParsing() {
 | 
			
		||||
		AllTests.parseFile("if.boppi");
 | 
			
		||||
		assertThat(AllTests.log, empty());
 | 
			
		||||
		BoppiTests.parseFile("if.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, empty());
 | 
			
		||||
 | 
			
		||||
		AllTests.parseFile("while.boppi");
 | 
			
		||||
		assertThat(AllTests.log, empty());
 | 
			
		||||
		BoppiTests.parseFile("while.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, empty());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +28,11 @@ public class ConditionalTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctConditionalChecking() {
 | 
			
		||||
		AllTests.checkFile("if.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkFile("if.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkFile("while.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkFile("while.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -40,29 +40,29 @@ public class ConditionalTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void basicPrograms() {
 | 
			
		||||
		AllTests.compileAndRunString("print(5*3)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("15")));
 | 
			
		||||
		BoppiTests.compileAndRunString("print(5*3)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("15")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("print({var int x; x := 8; print(x)})");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("8", "8")));
 | 
			
		||||
		BoppiTests.compileAndRunString("print({var int x; x := 8; print(x)})");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("8", "8")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("print('T', 'e', 's', 't', '!')");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("T", "e", "s", "t", "!")));
 | 
			
		||||
		BoppiTests.compileAndRunString("print('T', 'e', 's', 't', '!')");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("T", "e", "s", "t", "!")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("var int x; var int y; x := 3*(y := 4); print(x,y)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("12", "4")));
 | 
			
		||||
		BoppiTests.compileAndRunString("var int x; var int y; x := 3*(y := 4); print(x,y)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("12", "4")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunFile("basicProgram1.boppi", "1", "T");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("T", "T")));
 | 
			
		||||
		BoppiTests.compileAndRunFile("basicProgram1.boppi", "1", "T");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("T", "T")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunFile("fibonacciIterative.boppi", "6");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("13")));
 | 
			
		||||
		BoppiTests.compileAndRunFile("fibonacciIterative.boppi", "6");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("13")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,8 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctExpressionParsing() {
 | 
			
		||||
		AllTests.parseFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(AllTests.log, empty());
 | 
			
		||||
		BoppiTests.parseFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, empty());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -29,20 +29,20 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongExpressionParsing() {
 | 
			
		||||
		AllTests.parseString("");
 | 
			
		||||
		assertThat(AllTests.log, not(empty()));
 | 
			
		||||
		BoppiTests.parseString("");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("~");
 | 
			
		||||
		assertThat(AllTests.log, not(empty()));
 | 
			
		||||
		BoppiTests.parseString("~");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("0A");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("0A");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("do");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("do");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("true true");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("true true");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -50,8 +50,8 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctExpressionChecking() {
 | 
			
		||||
		AllTests.checkFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -59,20 +59,20 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongExpressionChecking() {
 | 
			
		||||
		AllTests.checkString("+true");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("+true");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("5 || true");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("5 || true");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("6 + 'c'");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("6 + 'c'");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("4 + print(5, 6)");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("4 + print(5, 6)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("print(print(3, 5))");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("print(print(3, 5))");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -80,16 +80,16 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctExpressionGeneration() {
 | 
			
		||||
		AllTests.compileAndRunFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunFile("simpleExpression.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		int n = 12;
 | 
			
		||||
		String expression = StringUtils.repeat("1+(", n) + "1" + StringUtils.repeat(")", n);
 | 
			
		||||
 | 
			
		||||
		AllTests.withWarnings(() -> {
 | 
			
		||||
			AllTests.compileAndRunString("print(" + expression + ")", "" + n);
 | 
			
		||||
			assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
			assertThat(AllTests.log.get(0).getLevel(), is(Level.WARNING));
 | 
			
		||||
		BoppiTests.withWarnings(() -> {
 | 
			
		||||
			BoppiTests.compileAndRunString("print(" + expression + ")", "" + n);
 | 
			
		||||
			assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
			assertThat(BoppiTests.log.get(0).getLevel(), is(Level.WARNING));
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -98,9 +98,9 @@ public class ExpressionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongExpressionGeneration() {
 | 
			
		||||
		AllTests.compileAndRunString("1/0");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		assertThat(AllTests.log.get(0).getMessage(), containsString("zero"));
 | 
			
		||||
		BoppiTests.compileAndRunString("1/0");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
		assertThat(BoppiTests.log.get(0).getMessage(), containsString("zero"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,214 @@
 | 
			
		|||
package pp.s1184725.boppi.test;
 | 
			
		||||
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
 | 
			
		||||
import static org.hamcrest.MatcherAssert.assertThat;
 | 
			
		||||
import static org.hamcrest.Matchers.*;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import pp.iloc.*;
 | 
			
		||||
import pp.iloc.eval.Machine;
 | 
			
		||||
import pp.iloc.model.Program;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for the ILOC simple allocator (memlib.iloc).
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Frank Wibbelink
 | 
			
		||||
 */
 | 
			
		||||
public class ILOCAllocatorTest {
 | 
			
		||||
	/**
 | 
			
		||||
	 * Default free memory (free slot size must report this value when nothing
 | 
			
		||||
	 * is allocated).
 | 
			
		||||
	 */
 | 
			
		||||
	private static final int FREEMEM = 0XFF;
 | 
			
		||||
	private static final int HEADER = 8;
 | 
			
		||||
	private static final int FIRSTPTR = 28;
 | 
			
		||||
	private static final int FIRSTSLOT = 32;
 | 
			
		||||
	private static final int SIZEOFFSET = 4;
 | 
			
		||||
	private static final int REFOFFSET = -8;
 | 
			
		||||
 | 
			
		||||
	private static final String obj1 = "r_obj1", obj2 = "r_obj2", obj3 = "r_obj3";
 | 
			
		||||
 | 
			
		||||
	private int returnAddress = 0;
 | 
			
		||||
	private Machine vm;
 | 
			
		||||
 | 
			
		||||
	private String malloc(int size, String reg) {
 | 
			
		||||
		returnAddress++;
 | 
			
		||||
		String s = "";
 | 
			
		||||
		s += "loadI 0 => r0\n";
 | 
			
		||||
		s += "loadI " + size + " => r1\n";
 | 
			
		||||
		s += "storeAI r1 => r0, 4\n";
 | 
			
		||||
		s += "loadI #end" + returnAddress + " => r2\n";
 | 
			
		||||
		s += "storeAI r2 => r0, 0\n";
 | 
			
		||||
		s += "jumpI -> memalloc\n";
 | 
			
		||||
		s += "end" + returnAddress + ": loadAI r0,16 => " + reg + "\n";
 | 
			
		||||
		if (size >= 4) {
 | 
			
		||||
			s += "loadI " + 0xDADACAFE + " => r2\n";
 | 
			
		||||
			s += "storeAI r2 => " + reg + ",0\n";
 | 
			
		||||
		}
 | 
			
		||||
		s += "\n";
 | 
			
		||||
		return s;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String incRef(String reg) {
 | 
			
		||||
		returnAddress++;
 | 
			
		||||
		String s = "";
 | 
			
		||||
		s += "loadI 0 => r0\n";
 | 
			
		||||
		s += "storeAI " + reg + " => r0, 4\n";
 | 
			
		||||
		s += "loadI #end" + returnAddress + " => r2\n";
 | 
			
		||||
		s += "storeAI r2 => r0, 0\n";
 | 
			
		||||
		s += "jumpI -> memaddref\n";
 | 
			
		||||
		s += "end" + returnAddress + ": nop\n";
 | 
			
		||||
		s += "\n";
 | 
			
		||||
		return s;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String free(String reg) {
 | 
			
		||||
		returnAddress++;
 | 
			
		||||
		String s = "";
 | 
			
		||||
		s += "loadI 0 => r0\n";
 | 
			
		||||
		s += "storeAI " + reg + " => r0, 4\n";
 | 
			
		||||
		s += "loadI #end" + returnAddress + " => r2\n";
 | 
			
		||||
		s += "storeAI r2 => r0, 0\n";
 | 
			
		||||
		s += "jumpI -> memfree\n";
 | 
			
		||||
		s += "end" + returnAddress + ": nop\n";
 | 
			
		||||
		s += "\n";
 | 
			
		||||
		return s;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void sim(String code) {
 | 
			
		||||
		try {
 | 
			
		||||
			String memlib = new String(
 | 
			
		||||
					Files.readAllBytes(BoppiTests.TEST_PROGRAM_LOCATION.resolve("../../memlib.iloc")));
 | 
			
		||||
			Program program = Assembler.instance().assemble(memlib + "\n" + code);
 | 
			
		||||
			vm = new Machine();
 | 
			
		||||
			vm.setSize((FREEMEM + FIRSTSLOT + HEADER) * 2);
 | 
			
		||||
			Simulator sim = new Simulator(program, vm);
 | 
			
		||||
			sim.run();
 | 
			
		||||
		} catch (Exception e) {
 | 
			
		||||
			throw new RuntimeException(e);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests whether memlib correctly compiles and initialises.
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void compileAndRun() {
 | 
			
		||||
		sim("");
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(FIRSTSLOT));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests whether memlib correctly allocates and deallocates at the end of
 | 
			
		||||
	 * used memory Tests whether memlib correctly merges deallocated memory with
 | 
			
		||||
	 * the free slot at the end.
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void simpleMallocFree() {
 | 
			
		||||
		sim(malloc(11, obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT)));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM - (HEADER + 11)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT)));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM - (HEADER + 11) - (HEADER + 7)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj2));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj2) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests whether memlib correctly halts the machine if freeing wrong
 | 
			
		||||
	 * addresses or using null pointers.
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void incorrectTests() {
 | 
			
		||||
		sim(malloc(11, obj1) + free(obj1) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(not(0)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + incRef("r0"));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(not(0)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + free("r0"));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(not(0)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests whether memlib correctly allocates and deallocates memory in the
 | 
			
		||||
	 * middle of used memory. Tests whether memlib correctly merges deallocated
 | 
			
		||||
	 * memory with previous and next slots. Tests whether memlib correctly uses
 | 
			
		||||
	 * free slots that are either exactly the requested size or fit at least a
 | 
			
		||||
	 * new free slot.
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void discontinuousMemory() {
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(not(0)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj1) + free(obj2));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj1) + malloc(11, obj3));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM - (HEADER + 11) - (HEADER + 7)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj1) + malloc(10, obj3));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(not(0)));
 | 
			
		||||
		assertThat(vm.load(vm.load(vm.load(FIRSTPTR)) + SIZEOFFSET),
 | 
			
		||||
				is(FREEMEM - (HEADER + 11) - (HEADER + 7) - (HEADER + 10)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + malloc(7, obj2) + free(obj1) + malloc(1, obj3) + malloc(2, obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT)));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR)), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM - (HEADER + 1) - (HEADER + 2) - (HEADER + 7)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tests whether memlib correctly tracks reference counts.
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void referenceCounting() {
 | 
			
		||||
		sim(malloc(11, obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.getReg(obj1) + REFOFFSET), is(1));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + incRef(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(vm.getReg(obj1) + REFOFFSET), is(2));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + incRef(obj1) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT)));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(not(FREEMEM)));
 | 
			
		||||
 | 
			
		||||
		sim(malloc(11, obj1) + incRef(obj1) + free(obj1) + free(obj1));
 | 
			
		||||
		assertThat(vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(vm.load(FIRSTPTR), is(FIRSTSLOT));
 | 
			
		||||
		assertThat(vm.load(vm.load(FIRSTPTR) + SIZEOFFSET), is(FREEMEM));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -16,23 +16,23 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctFunctionParsing() {
 | 
			
		||||
		AllTests.parseString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function int id(int a) a; id(1)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("function int id(int a) a; id(1)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("var int a; a := 1; function int const() a; const()");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("var int a; a := 1; function int const() a; const()");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.parseString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -40,14 +40,14 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongFunctionParsing() {
 | 
			
		||||
		AllTests.parseString("function doNothing(int a, char b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("function doNothing(int a, char b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function char add(int a, int b);");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("function char add(int a, int b);");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("function int add(int a, int b) a+b; add(4,)");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("function int add(int a, int b) a+b; add(4,)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -55,23 +55,23 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctFunctionChecking() {
 | 
			
		||||
		AllTests.checkString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function int id(int a) a; id(1); 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("function int id(int a) a; id(1); 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("var int a; function int const() a; 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("var int a; function int const() a; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}; 0");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -79,14 +79,14 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongFunctionChecking() {
 | 
			
		||||
		AllTests.checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function char add(int a, int b) a+b; print(add(4, 5))");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("function char add(int a, int b) a+b; print(add(4, 5))");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -94,26 +94,26 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctSimpleFunctionGeneration() {
 | 
			
		||||
		AllTests.compileAndRunString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunString("function int id(int a) a; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("function int id(int a) a; id(1); 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunString("function int id(int a) a; id(1); 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("var int a; function int const(int b) a; 1");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunString("var int a; function int const(int b) a; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("var int a; a := 1; function int const(int b) a; print(const(4))");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("1")));
 | 
			
		||||
		BoppiTests.compileAndRunString("var int a; a := 1; function int const(int b) a; print(const(4))");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("1")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("10")));
 | 
			
		||||
		BoppiTests.compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("10")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("A")));
 | 
			
		||||
		BoppiTests.compileAndRunString("function char const(char a, char b) a; print(const('A', 'T'))");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("A")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -122,16 +122,16 @@ public class SimpleFunctionTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctComplexFunctionGeneration() {
 | 
			
		||||
		AllTests.compileAndRunString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}; 0");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunFile("recursiveFactorial.boppi", "5");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("120")));
 | 
			
		||||
		BoppiTests.compileAndRunFile("recursiveFactorial.boppi", "5");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("120")));
 | 
			
		||||
 | 
			
		||||
		AllTests.compileAndRunFile("simpleFunctionPassing.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		assertThat(AllTests.out, is(arrayContaining("40", "104", "1", "2", "8")));
 | 
			
		||||
		BoppiTests.compileAndRunFile("simpleFunctionPassing.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("40", "104", "1", "2", "8")));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,8 +16,8 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctVariableParsing() {
 | 
			
		||||
		AllTests.parseFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(AllTests.log, empty());
 | 
			
		||||
		BoppiTests.parseFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, empty());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -25,17 +25,17 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongVariableParsing() {
 | 
			
		||||
		AllTests.parseString("var");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("var");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("var bool 5");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.parseString("var bool 5");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("var 'c' varname");
 | 
			
		||||
		assertThat(AllTests.log, not(empty()));
 | 
			
		||||
		BoppiTests.parseString("var 'c' varname");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		AllTests.parseString("var bool; true true;");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(2));
 | 
			
		||||
		BoppiTests.parseString("var bool; true true;");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -43,8 +43,8 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctScopeParsing() {
 | 
			
		||||
		AllTests.parseFile("simpleScope.boppi");
 | 
			
		||||
		assertThat(AllTests.log, empty());
 | 
			
		||||
		BoppiTests.parseFile("simpleScope.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, empty());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -52,8 +52,8 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctVariableChecking() {
 | 
			
		||||
		AllTests.checkFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -61,20 +61,20 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongVariableChecking() {
 | 
			
		||||
		AllTests.checkString("var bool name; name := 5");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var bool name; name := 5");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("undefinedName");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("undefinedName");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("var undefinedType name; 1");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var undefinedType name; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("var bool endsWithDeclaration;");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var bool endsWithDeclaration;");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("var bool var1; var var1 var2; var2 := 'c' ");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var bool var1; var var1 var2; var2 := 'c' ");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -82,8 +82,8 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctScopeChecking() {
 | 
			
		||||
		AllTests.checkFile("simpleScope.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.checkFile("simpleScope.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -91,14 +91,14 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongScopeChecking() {
 | 
			
		||||
		AllTests.checkString("var bool var1; var bool var1; 1");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var bool var1; var bool var1; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("var bool var1; var char var1; 1");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("var bool var1; var char var1; 1");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		AllTests.checkString("{ var int var1; var1 := 4}; var int var2; var1");
 | 
			
		||||
		assertThat(AllTests.log, hasSize(1));
 | 
			
		||||
		BoppiTests.checkString("{ var int var1; var1 := 4}; var int var2; var1");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -106,8 +106,8 @@ public class SimpleVariableTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctVariableGeneration() {
 | 
			
		||||
		AllTests.compileAndRunFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(AllTests.log, is(empty()));
 | 
			
		||||
		BoppiTests.compileAndRunFile("simpleVariable.boppi");
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue