changed array implementation (size is no longer part of type)
This commit is contained in:
		
							parent
							
								
									68093f96e9
								
							
						
					
					
						commit
						c503ff31c5
					
				| 
						 | 
				
			
			@ -102,6 +102,14 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Visits the parse tree, then records the returned type in the type
 | 
			
		||||
	 * annotations and returns it too.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param tree
 | 
			
		||||
	 *            the tree to visit
 | 
			
		||||
	 * @return the evaluated type of the tree
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visit(ParseTree tree) {
 | 
			
		||||
		Type type = super.visit(tree);
 | 
			
		||||
| 
						 | 
				
			
			@ -150,16 +158,13 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
			Variable<Type> var = an.symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type()));
 | 
			
		||||
			var.setConstant(ctx.CONSTANT() != null);
 | 
			
		||||
			an.variables.put(ctx, var);
 | 
			
		||||
			an.variableRoot.put(var, ctx.getParent());
 | 
			
		||||
			an.variableRoot.put(var, ctx.getParent().getParent());
 | 
			
		||||
 | 
			
		||||
			if (var.getType() instanceof TupleType)
 | 
			
		||||
				log.severe(getError(ctx, Messages.getString("BoppiChecker.4"), //$NON-NLS-1$
 | 
			
		||||
						BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.BOOLTYPE),
 | 
			
		||||
						BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.CHARTYPE),
 | 
			
		||||
						BoppiLexer.VOCABULARY.getLiteralName(BoppiLexer.INTTYPE)));
 | 
			
		||||
 | 
			
		||||
			if (var.getType() instanceof ReferenceType)
 | 
			
		||||
				var.assign();
 | 
			
		||||
		} catch (SymbolTableException e) {
 | 
			
		||||
			log.severe(getError(ctx, e.getMessage()));
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -200,6 +205,13 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
		return SimpleType.VOID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitDefineArray(DefineArrayContext ctx) {
 | 
			
		||||
		checkConstraint(visit(ctx.size), SimpleType.INT, ctx);
 | 
			
		||||
 | 
			
		||||
		return new ArrayType(visit(ctx.type()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitGetVariable(GetVariableContext ctx) {
 | 
			
		||||
		return visit(ctx.variable());
 | 
			
		||||
| 
						 | 
				
			
			@ -301,6 +313,16 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
		return SimpleType.VOID;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitLiteralArray(LiteralArrayContext ctx) {
 | 
			
		||||
		Type elementType = visit(ctx.expr(0));
 | 
			
		||||
 | 
			
		||||
		for (int i = 1; i < ctx.expr().size(); i++)
 | 
			
		||||
			checkConstraint(visit(ctx.expr(i)), elementType, ctx);
 | 
			
		||||
 | 
			
		||||
		return new ArrayType(elementType);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitLiteralBoolean(LiteralBooleanContext ctx) {
 | 
			
		||||
		return SimpleType.BOOL;
 | 
			
		||||
| 
						 | 
				
			
			@ -390,15 +412,7 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Type visitTypeArray(TypeArrayContext ctx) {
 | 
			
		||||
		int size = 0;
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			size = Integer.parseInt(ctx.LITERAL10().getText());
 | 
			
		||||
		} catch (NumberFormatException e) {
 | 
			
		||||
			log.severe(getError(ctx, Messages.getString("BoppiChecker.6"), ctx.LITERAL10().getText())); //$NON-NLS-1$
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return new ArrayType(size, visit(ctx.type()));
 | 
			
		||||
		return new ArrayType(visit(ctx.type()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,22 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
			OFFSET_RETURN_VAL = new Num(-12), OFFSET_AL = new Num(-16), OFFSET_FUNCREF_ADDR = ZERO,
 | 
			
		||||
			OFFSET_FUNCREF_ARP = new Num(4), OFFSET_FUNCREF_ARSIZE = new Num(8), OFFSET_REF_COUNT = new Num(-8),
 | 
			
		||||
			OFFSET_REF_SIZE = new Num(-4);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Unknown type used in a read expression
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Num ERROR_INPUT_UNKNOWN_TYPE = new Num(0x72656164);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Unknown type used in a print expression
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Num ERROR_OUTPUT_UNKNOWN_TYPE = new Num(0x77726974);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Array out of bounds
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Num ERROR_OUT_OF_BOUNDS = new Num(0x616f6f62);
 | 
			
		||||
	/**
 | 
			
		||||
	 * Negative array size
 | 
			
		||||
	 */
 | 
			
		||||
	public static final Num ERROR_ILLEGAL_ARRAY_SIZE = new Num(0x616e737a);
 | 
			
		||||
 | 
			
		||||
	private Program prog;
 | 
			
		||||
	private Annotations an;
 | 
			
		||||
| 
						 | 
				
			
			@ -531,29 +547,6 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitDeclare(DeclareContext ctx) {
 | 
			
		||||
		Variable<Type> var = an.variables.get(ctx);
 | 
			
		||||
		Type t = var.getType();
 | 
			
		||||
 | 
			
		||||
		if (t instanceof ReferenceType) {
 | 
			
		||||
 | 
			
		||||
			regPool.withReg((addr) -> {
 | 
			
		||||
				emit("load var address", OpCode.addI, arp, new Num(var.getOffset()), addr); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
				if (t instanceof ArrayType) {
 | 
			
		||||
					ArrayType type = (ArrayType) t;
 | 
			
		||||
					regPool.withReg((temp) -> {
 | 
			
		||||
						malloc(temp, type.getReferenceSize());
 | 
			
		||||
						emit("link array", OpCode.store, temp, addr); //$NON-NLS-1$
 | 
			
		||||
					});
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Declare named function:
 | 
			
		||||
	 * <ol>
 | 
			
		||||
| 
						 | 
				
			
			@ -570,7 +563,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitDeclareFunction(DeclareFunctionContext ctx) {
 | 
			
		||||
		ReferenceType type = (ReferenceType) an.variables.get(ctx).getType();
 | 
			
		||||
		FunctionType funcType = (FunctionType) an.variables.get(ctx).getType();
 | 
			
		||||
		String base = "define " + ctx.IDENTIFIER().getText() + " - "; //$NON-NLS-1$ //$NON-NLS-2$
 | 
			
		||||
 | 
			
		||||
		Label skip = makeLabel("s"); //$NON-NLS-1$
 | 
			
		||||
| 
						 | 
				
			
			@ -579,7 +572,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
 | 
			
		||||
		Reg result = visit(ctx.body);
 | 
			
		||||
 | 
			
		||||
		if (((FunctionType) an.variables.get(ctx).getType()).getReturn() != SimpleType.VOID)
 | 
			
		||||
		if (funcType.getReturn() != SimpleType.VOID)
 | 
			
		||||
			emit(base + "move result", OpCode.storeAI, result, arp, OFFSET_RETURN_VAL); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
		if (PROPER_CLEANUP_INSTEAD_OF_PROPER_CLOSURES)
 | 
			
		||||
| 
						 | 
				
			
			@ -607,7 +600,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
		emit(base + "skip target", skip, OpCode.nop); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
		regPool.withReg((r1, r2) -> {
 | 
			
		||||
			malloc(r2, type.getReferenceSize());
 | 
			
		||||
			malloc(r2, funcType.getReferenceSize());
 | 
			
		||||
			emit(base + "load target address", OpCode.loadI, new Num(callAddress), r1); //$NON-NLS-1$
 | 
			
		||||
			emit(base + "set target address", OpCode.storeAI, r1, r2, OFFSET_FUNCREF_ADDR); //$NON-NLS-1$
 | 
			
		||||
			emit(base + "copy ARP", OpCode.storeAI, arp, r2, OFFSET_FUNCREF_ARP); //$NON-NLS-1$
 | 
			
		||||
| 
						 | 
				
			
			@ -622,6 +615,32 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
		return null;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitDefineArray(DefineArrayContext ctx) {
 | 
			
		||||
		Type elementType = ((ArrayType) an.types.get(ctx)).getType();
 | 
			
		||||
		Reg arrSize = visit(ctx.size);
 | 
			
		||||
 | 
			
		||||
		emit("produce array size", OpCode.multI, arrSize, new Num(elementType.getSize()), arrSize); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
		return regPool.blockReg(arrSize, () -> regPool.withReg((temp) -> {
 | 
			
		||||
			Label validSize = makeLabel("aszt"), invalidSize = makeLabel("aszf");
 | 
			
		||||
			emit("check size non negative", OpCode.cmp_GE, arrSize, RegisterPool.ZERO, temp);
 | 
			
		||||
			emit("", OpCode.cbr, temp, validSize, invalidSize);
 | 
			
		||||
			emit("invalid array size", invalidSize, OpCode.haltI, ERROR_ILLEGAL_ARRAY_SIZE);
 | 
			
		||||
			emit("valid array size", validSize, OpCode.nop);
 | 
			
		||||
 | 
			
		||||
			malloc(temp, arrSize);
 | 
			
		||||
		}));
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Loads the value on the address pointed to by the variable context.
 | 
			
		||||
	 * Because the array length is not stored by itself, it will be calculated
 | 
			
		||||
	 * here from the size property.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @see BoppiBaseVisitor#visitGetVariable(GetVariableContext)
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitGetVariable(GetVariableContext ctx) {
 | 
			
		||||
		Type type = an.types.get(ctx);
 | 
			
		||||
| 
						 | 
				
			
			@ -635,6 +654,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
				incrementReference(type, result);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
		if (ctx.variable() instanceof VariablePropertyContext) {
 | 
			
		||||
			VariablePropertyContext vpctx = (VariablePropertyContext) ctx.variable();
 | 
			
		||||
			Type varType = an.types.get(vpctx.variable());
 | 
			
		||||
 | 
			
		||||
			if (varType instanceof ArrayType)
 | 
			
		||||
				emit("divide by element size", OpCode.divI, result, //$NON-NLS-1$
 | 
			
		||||
						new Num(((ArrayType) varType).getType().getSize()), result);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -717,9 +745,15 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
 | 
			
		||||
				return regPool.withReg((i, temp1) -> {
 | 
			
		||||
					regPool.withReg((temp2) -> {
 | 
			
		||||
						Label cond = makeLabel("aeqc"), loop = makeLabel("aeql"), end = makeLabel("aeqe"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 | 
			
		||||
						Label equalSize = makeLabel("aeqs"), cond = makeLabel("aeqc"), loop = makeLabel("aeql"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 | 
			
		||||
								end = makeLabel("aeqe"); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
						emit("iterate from 0", OpCode.loadI, ZERO, i); //$NON-NLS-1$
 | 
			
		||||
						emit("load size lhs", OpCode.loadAI, lhs, OFFSET_REF_SIZE, temp1); //$NON-NLS-1$
 | 
			
		||||
						emit("load size rhs", OpCode.loadAI, rhs, OFFSET_REF_SIZE, temp2); //$NON-NLS-1$
 | 
			
		||||
						emit("compare array sizes", OpCode.cmp_EQ, temp1, temp2, temp1); //$NON-NLS-1$
 | 
			
		||||
						emit("loop if equal", OpCode.cbr, temp1, equalSize, end); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
						emit("iterate from 0", equalSize, OpCode.loadI, ZERO, i); //$NON-NLS-1$
 | 
			
		||||
						emit("equality true", OpCode.loadI, new Num(1), temp1); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
						emit("load arr size", cond, OpCode.loadAI, lhs, OFFSET_REF_SIZE, temp2); //$NON-NLS-1$
 | 
			
		||||
| 
						 | 
				
			
			@ -767,6 +801,26 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
		return visit(ctx.expr());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitLiteralArray(LiteralArrayContext ctx) {
 | 
			
		||||
		int elements = ctx.expr().size();
 | 
			
		||||
		int elementSize = ((ArrayType) an.types.get(ctx)).getType().getSize();
 | 
			
		||||
 | 
			
		||||
		return regPool.withReg((addr) -> {
 | 
			
		||||
			malloc(addr, elements * elementSize);
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < elements; i++) {
 | 
			
		||||
				Reg result = visit(ctx.expr(i));
 | 
			
		||||
				Num offset = new Num(i * elementSize);
 | 
			
		||||
 | 
			
		||||
				if (elementSize == 1)
 | 
			
		||||
					emit("store array element", OpCode.cstoreAI, result, addr, offset); //$NON-NLS-1$
 | 
			
		||||
				else
 | 
			
		||||
					emit("store array element", OpCode.storeAI, result, addr, offset); //$NON-NLS-1$
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Reg visitLiteralBoolean(LiteralBooleanContext ctx) {
 | 
			
		||||
		return regPool.withReg((reg) -> {
 | 
			
		||||
| 
						 | 
				
			
			@ -852,7 +906,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
					emit("save to var " + expr.getText(), OpCode.cstore, temp, addr); //$NON-NLS-1$
 | 
			
		||||
				});
 | 
			
		||||
			else
 | 
			
		||||
				emit("reading unknown type", OpCode.haltI, new Num(0x72656164)); //$NON-NLS-1$
 | 
			
		||||
				emit("reading unknown type", OpCode.haltI, ERROR_INPUT_UNKNOWN_TYPE); //$NON-NLS-1$
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return res;
 | 
			
		||||
| 
						 | 
				
			
			@ -897,7 +951,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
					emit("check array index", OpCode.cmp_GE, offset, RegisterPool.ZERO, r2); //$NON-NLS-1$
 | 
			
		||||
					emit("check array index", OpCode.and, r1, r2, r2); //$NON-NLS-1$
 | 
			
		||||
					emit("check array index", OpCode.cbr, r2, inBounds, outOfBounds); //$NON-NLS-1$
 | 
			
		||||
					emit("array index out of bounds", outOfBounds, OpCode.haltI, new Num(0x616f6f62)); //$NON-NLS-1$
 | 
			
		||||
					emit("array index out of bounds", outOfBounds, OpCode.haltI, ERROR_OUT_OF_BOUNDS); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
					emit("multiply index by size", inBounds, OpCode.multI, offset, new Num(type.getType().getSize()), //$NON-NLS-1$
 | 
			
		||||
							offset);
 | 
			
		||||
| 
						 | 
				
			
			@ -914,8 +968,10 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
		Type innerType = an.types.get(ctx.variable());
 | 
			
		||||
		Reg addr = visit(ctx.variable());
 | 
			
		||||
 | 
			
		||||
		emit("get object address", OpCode.load, addr, addr); //$NON-NLS-1$
 | 
			
		||||
 | 
			
		||||
		if (innerType instanceof ArrayType) {
 | 
			
		||||
			emit("get size", OpCode.loadAI, addr, OFFSET_REF_SIZE, addr); //$NON-NLS-1$
 | 
			
		||||
			emit("add size offset", OpCode.addI, addr, OFFSET_REF_SIZE, addr); //$NON-NLS-1$
 | 
			
		||||
			return addr;
 | 
			
		||||
		} else {
 | 
			
		||||
			return addr;
 | 
			
		||||
| 
						 | 
				
			
			@ -984,7 +1040,7 @@ public class BoppiGenerator extends BoppiBaseVisitor<Reg> {
 | 
			
		|||
						emit("print character", OpCode.cout, new Str("")); //$NON-NLS-1$ //$NON-NLS-2$
 | 
			
		||||
					});
 | 
			
		||||
				} else {
 | 
			
		||||
					emit("writing unknown type", OpCode.haltI, new Num(0x77726974)); //$NON-NLS-1$
 | 
			
		||||
					emit("writing unknown type", OpCode.haltI, ERROR_OUTPUT_UNKNOWN_TYPE); //$NON-NLS-1$
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (!expr.equals(ctx.expr(ctx.expr().size() - 1)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,16 +35,18 @@ expr
 | 
			
		|||
	| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
 | 
			
		||||
	| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
 | 
			
		||||
	| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
 | 
			
		||||
	| LAMBDA IDENTIFIER+ ARROW expr #lambda
 | 
			
		||||
	| LAMBDA IDENTIFIER+ ARROW body=expr #lambda
 | 
			
		||||
	| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
 | 
			
		||||
	| variable #getVariable
 | 
			
		||||
	| ARRAY PAROPEN type LISTDELIM size=expr PARCLOSE #defineArray
 | 
			
		||||
	| ARROPEN expr (LISTDELIM expr)* ARRCLOSE #literalArray
 | 
			
		||||
	| LITERAL10 #literalInteger
 | 
			
		||||
	| CHAR #literalCharacter
 | 
			
		||||
	| (TRUE|FALSE) #literalBoolean
 | 
			
		||||
	;
 | 
			
		||||
 | 
			
		||||
type
 | 
			
		||||
	: ARROPEN LITERAL10 ARRCLOSE type #typeArray
 | 
			
		||||
	: type ARROPEN ARRCLOSE #typeArray
 | 
			
		||||
	| type ARROW type #typeFunction
 | 
			
		||||
	| staticType=(INTTYPE | BOOLTYPE | CHARTYPE) #typeSimple
 | 
			
		||||
	| PAROPEN (type (LISTDELIM type)*)? PARCLOSE #typeTuple
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,10 +28,16 @@ public class ArrayTest {
 | 
			
		|||
		BoppiTests.parseString("var []int arr; 0");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.parseString("var int a; a := 5; var [5][a]int arr; 0");
 | 
			
		||||
		BoppiTests.parseString("var int[6] arr; 0");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.parseString("var [4]int arr; (arr)[5]");
 | 
			
		||||
		BoppiTests.parseString("var int[[]] a; 0");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.parseString("var int[] arr; (arr)[5]");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.parseString("var int[] arr; arr := array(5)");
 | 
			
		||||
		assertThat(BoppiTests.log, hasSize(1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,13 +58,31 @@ public class ArrayTest {
 | 
			
		|||
		BoppiTests.checkString("var int a; a[5]");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var [5]int arr; arr := 5");
 | 
			
		||||
		BoppiTests.checkString("var int[] arr; arr := 5");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var [5]int arr; arr[4][2] := 5");
 | 
			
		||||
		BoppiTests.checkString("var int[] arr; arr[4][2] := 5");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var int a; var int[5] arr; a := arr");
 | 
			
		||||
		BoppiTests.checkString("var int a; var int[] arr; a := arr");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var int[] arr; arr := array(char, 5)");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var int[] arr; arr := ['a', 'c']");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Uninitialized arrays
 | 
			
		||||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongArrayChecking2() {
 | 
			
		||||
		BoppiTests.checkString("var int[] a; a[5]");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.checkString("var int[] a; var int[] b; a := b; a[0]");
 | 
			
		||||
		assertThat(BoppiTests.log, not(empty()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,11 +91,16 @@ public class ArrayTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void correctArrayGeneration() {
 | 
			
		||||
		BoppiTests.compileAndRunString("var int n; read(n); var int[] arr; arr := array(int, n); print(arr.length)", "7");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("7")));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.compileAndRunFile("simpleArray.boppi");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
		assertThat(BoppiTests.out, is(arrayContaining("9", "H", "a", "Y")));
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
		BoppiTests.compileAndRunFile("complexArray.boppi");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(0));
 | 
			
		||||
		assertThat(BoppiTests.log, is(empty()));
 | 
			
		||||
| 
						 | 
				
			
			@ -84,10 +113,13 @@ public class ArrayTest {
 | 
			
		|||
	 */
 | 
			
		||||
	@Test
 | 
			
		||||
	public void wrongArrayGeneration() {
 | 
			
		||||
		BoppiTests.compileAndRunString("var [10]int arr; arr[10] := 5");
 | 
			
		||||
		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[10] := 5");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
 | 
			
		||||
		
 | 
			
		||||
		BoppiTests.compileAndRunString("var [10]int arr; arr[-1]");
 | 
			
		||||
 | 
			
		||||
		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, 10); arr[-1]");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
 | 
			
		||||
 | 
			
		||||
		BoppiTests.compileAndRunString("var int[] arr; arr := array(int, -1)");
 | 
			
		||||
		assertThat(BoppiTests.vm.getInterrupt(), is(not(0)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,33 +2,29 @@ var int i;
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
// multi-dimensional array
 | 
			
		||||
// like multi-dimensional arrays in most languages, they are arrays of (n-1)-dimensional array references, so they won't be initialised by default
 | 
			
		||||
var [2]int arr1_1;
 | 
			
		||||
var arr1_1 arr1_2;
 | 
			
		||||
var int[][][] arr3;
 | 
			
		||||
arr3 := [
 | 
			
		||||
    [[1,0],
 | 
			
		||||
     [0,1]],
 | 
			
		||||
    [[1,1],
 | 
			
		||||
     [0,1]],
 | 
			
		||||
    [[3,2],
 | 
			
		||||
     [2,3]]
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
var [8][2]int arr2_1;
 | 
			
		||||
var arr2_1 arr2_2;
 | 
			
		||||
arr3[0][0][0] := arr3[2][0][1] := 1337;
 | 
			
		||||
 | 
			
		||||
var [3][8][2]int arr3;
 | 
			
		||||
 | 
			
		||||
arr3[0] := arr2_1;
 | 
			
		||||
arr2_1[0] := arr1_1;
 | 
			
		||||
 | 
			
		||||
arr3[2] := arr2_2;
 | 
			
		||||
arr2_2[7] := arr1_2;
 | 
			
		||||
 | 
			
		||||
arr3[0][0][0] := arr3[2][7][1] := 1337;
 | 
			
		||||
 | 
			
		||||
print(arr3[2][7][1]);
 | 
			
		||||
print(arr3[2][0][1]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// array passing
 | 
			
		||||
var [2][4]int target;
 | 
			
		||||
var int[][] target; target := array(int[], 2);
 | 
			
		||||
 | 
			
		||||
function [4]int populate(int start) {
 | 
			
		||||
    var [4]int arr;
 | 
			
		||||
function int[] populate(int start) {
 | 
			
		||||
    var int[] arr; arr := array(int, 4);
 | 
			
		||||
    var int i; i := 0;
 | 
			
		||||
 | 
			
		||||
    while i < 4 do
 | 
			
		||||
        arr[i] := start+i;
 | 
			
		||||
        i := i+1;
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +44,7 @@ print(target[1][3]);
 | 
			
		|||
var target target2;
 | 
			
		||||
target2 := target;
 | 
			
		||||
 | 
			
		||||
var [4]int firstRow;
 | 
			
		||||
var int[] firstRow; firstRow := array(int, 4);
 | 
			
		||||
firstRow := target2[0];
 | 
			
		||||
 | 
			
		||||
print(firstRow[2]);
 | 
			
		||||
| 
						 | 
				
			
			@ -56,13 +52,11 @@ print(firstRow[2]);
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
// function array
 | 
			
		||||
var [10]int arr10;
 | 
			
		||||
 | 
			
		||||
function arr10 mapArray((int)->int f, arr10 array) {
 | 
			
		||||
    var arr10 newArr;
 | 
			
		||||
function int[] mapArray((int)->int f, int[] arr) {
 | 
			
		||||
    var int[] newArr; newArr := array(int, arr.length);
 | 
			
		||||
    var int i; i := 0;
 | 
			
		||||
    while i < 10 do
 | 
			
		||||
        newArr[i] := f(array[i]);
 | 
			
		||||
    while i < arr.length do
 | 
			
		||||
        newArr[i] := f(arr[i]);
 | 
			
		||||
        i := i+1;
 | 
			
		||||
    od;
 | 
			
		||||
    newArr
 | 
			
		||||
| 
						 | 
				
			
			@ -70,10 +64,10 @@ function arr10 mapArray((int)->int f, arr10 array) {
 | 
			
		|||
 | 
			
		||||
function int increment(int a) a+1;
 | 
			
		||||
 | 
			
		||||
var arr10 myArray;
 | 
			
		||||
var int[] myArray; myArray := array(int, 9);
 | 
			
		||||
 | 
			
		||||
i := 0;
 | 
			
		||||
while i < 10 do
 | 
			
		||||
while i < myArray.length do
 | 
			
		||||
    myArray[i] := i*i+10;
 | 
			
		||||
    i := i+1;
 | 
			
		||||
od;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,46 +1,36 @@
 | 
			
		|||
//Recursive fibonacci with memoization closure
 | 
			
		||||
 | 
			
		||||
var int n;
 | 
			
		||||
function (int)->int memoizedFib() {
 | 
			
		||||
    var int[] memo;
 | 
			
		||||
    memo := array(int, 50);
 | 
			
		||||
 | 
			
		||||
var (int)->int fib;
 | 
			
		||||
 | 
			
		||||
function fib memoize(fib f) {
 | 
			
		||||
    var [50]int memo;
 | 
			
		||||
 | 
			
		||||
    var int i; i := 0; while i < 50 do
 | 
			
		||||
        memo[i] := 0;
 | 
			
		||||
        i := i+1;
 | 
			
		||||
    od;
 | 
			
		||||
 | 
			
		||||
    function int memoFib(int n) {
 | 
			
		||||
        if n >= 0 && n < 50 then
 | 
			
		||||
    function int fib(int n) {
 | 
			
		||||
        if n < 2 then
 | 
			
		||||
            1
 | 
			
		||||
        else
 | 
			
		||||
            if memo[n] > 0 then
 | 
			
		||||
                memo[n]
 | 
			
		||||
            else
 | 
			
		||||
                memo[n] := f(n)
 | 
			
		||||
                var int answer;
 | 
			
		||||
                answer := fib(n-1)+fib(n-2);
 | 
			
		||||
 | 
			
		||||
                if n < memo.length then
 | 
			
		||||
                  memo[n] := answer
 | 
			
		||||
                fi;
 | 
			
		||||
 | 
			
		||||
                answer
 | 
			
		||||
            fi
 | 
			
		||||
        else
 | 
			
		||||
            f(n)
 | 
			
		||||
        fi
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    memoFib
 | 
			
		||||
    fib
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function int fib_(int n) {
 | 
			
		||||
    if n < 2 then
 | 
			
		||||
        1
 | 
			
		||||
    else
 | 
			
		||||
        fib(n-1)+fib(n-2) //has to call `fib` instead of `fib_` because `fib_` is constant
 | 
			
		||||
    fi
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
fib := memoize(fib_);
 | 
			
		||||
 | 
			
		||||
var (int)->int myFib;
 | 
			
		||||
myFib := memoizedFib();
 | 
			
		||||
 | 
			
		||||
var int n;
 | 
			
		||||
read(n);
 | 
			
		||||
 | 
			
		||||
while n > 0 do
 | 
			
		||||
    print(fib(n));
 | 
			
		||||
    print(myFib(n));
 | 
			
		||||
    read(n)
 | 
			
		||||
od;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
var [5]int arr;
 | 
			
		||||
var int[] arr; arr := array(int, 5);
 | 
			
		||||
 | 
			
		||||
var int i; i := 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,13 +11,11 @@ print(arr[3]);
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var [2]char arr2;
 | 
			
		||||
arr2[0] := 'H';
 | 
			
		||||
arr2[1] := 'a';
 | 
			
		||||
var char[] arr2; arr2 := ['H', 'a'];
 | 
			
		||||
 | 
			
		||||
print(arr2[0], arr2[1]);
 | 
			
		||||
 | 
			
		||||
var [2]char arr3;
 | 
			
		||||
var char[] arr3; arr3 := array(char, 2);
 | 
			
		||||
arr3[1] := 'a';
 | 
			
		||||
arr3[0] := 'H';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,33 +3,24 @@ package pp.s1184725.boppi.type;
 | 
			
		|||
import pp.iloc.eval.Machine;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A vector type of fixed size. Takes a length and a type parameter.
 | 
			
		||||
 * A vector type of run-time defined size. Takes a type parameter.
 | 
			
		||||
 * 
 | 
			
		||||
 * @author Frank Wibbelink
 | 
			
		||||
 */
 | 
			
		||||
public class ArrayType implements ReferenceType {
 | 
			
		||||
	private int count;
 | 
			
		||||
	private Type elType;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a new array type with the given number of elements and their
 | 
			
		||||
	 * type.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param count
 | 
			
		||||
	 *            the number of elements
 | 
			
		||||
	 * @param type
 | 
			
		||||
	 *            the type of elements
 | 
			
		||||
	 */
 | 
			
		||||
	public ArrayType(int count, Type type) {
 | 
			
		||||
		this.count = count;
 | 
			
		||||
	public ArrayType(Type type) {
 | 
			
		||||
		this.elType = type;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int getReferenceSize() {
 | 
			
		||||
		return count * elType.getSize();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int getSize() {
 | 
			
		||||
		return Machine.INT_SIZE;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,12 +32,12 @@ public class ArrayType implements ReferenceType {
 | 
			
		|||
			return false;
 | 
			
		||||
 | 
			
		||||
		ArrayType other = (ArrayType) obj;
 | 
			
		||||
		return count == other.count && elType.equals(other.elType);
 | 
			
		||||
		return elType.equals(other.elType);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return elType.toString()+"["+count+"]";
 | 
			
		||||
		return elType.toString()+"[]";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,10 +27,14 @@ public class FunctionType implements ReferenceType {
 | 
			
		|||
	public int getSize() {
 | 
			
		||||
		return Machine.INT_SIZE;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the size of the function context.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @return the size (in bytes) of the function context
 | 
			
		||||
	 */
 | 
			
		||||
	public int getReferenceSize() {
 | 
			
		||||
		return 3*Machine.INT_SIZE;
 | 
			
		||||
		return 3 * Machine.INT_SIZE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,4 @@ package pp.s1184725.boppi.type;
 | 
			
		|||
 * @author Frank Wibbelink
 | 
			
		||||
 */
 | 
			
		||||
public interface ReferenceType extends Type {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the size of the object this type references.
 | 
			
		||||
	 * @return the size (in bytes) of the referenced object
 | 
			
		||||
	 */
 | 
			
		||||
	public int getReferenceSize();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue