check 'if' condition type, mark functions constant, improved tests

This commit is contained in:
User 2017-11-28 16:45:15 +01:00
parent eae3c68b51
commit 68093f96e9
12 changed files with 77 additions and 21 deletions

View File

@ -180,6 +180,7 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
FunctionType type = new FunctionType(returnType, parameterTypes); FunctionType type = new FunctionType(returnType, parameterTypes);
Variable<Type> func = an.symbols.put(ctx.name.getText(), type); Variable<Type> func = an.symbols.put(ctx.name.getText(), type);
func.setConstant(true);
func.assign(); func.assign();
an.variables.put(ctx, func); an.variables.put(ctx, func);
@ -207,7 +208,8 @@ public class BoppiChecker extends BoppiBaseVisitor<Type> {
@Override @Override
public Type visitIf(IfContext ctx) { public Type visitIf(IfContext ctx) {
return an.symbols.withScope(() -> { return an.symbols.withScope(() -> {
visit(ctx.cond); checkConstraint(visit(ctx.cond), SimpleType.BOOL, ctx.cond);
if (ctx.onFalse != null) { if (ctx.onFalse != null) {
Type trueType = an.symbols.withScope(() -> visit(ctx.onTrue)); Type trueType = an.symbols.withScope(() -> visit(ctx.onTrue));
Type falseType = an.symbols.withScope(() -> visit(ctx.onFalse)); Type falseType = an.symbols.withScope(() -> visit(ctx.onFalse));

View File

@ -16,7 +16,6 @@ stat
declareStat declareStat
: DECLARE CONSTANT? type IDENTIFIER #declare : DECLARE CONSTANT? type IDENTIFIER #declare
| FUNCTION (result=type)? name=IDENTIFIER PAROPEN parameters? PARCLOSE body=expr #declareFunction | FUNCTION (result=type)? name=IDENTIFIER PAROPEN parameters? PARCLOSE body=expr #declareFunction
| LAMBDA IDENTIFIER+ ARROW expr #lambda
; ;
assignStat assignStat
@ -36,6 +35,7 @@ expr
| OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write | OUT PAROPEN expr (LISTDELIM expr)* PARCLOSE #write
| IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if | IFOPEN cond=stats IFTRUE onTrue=stats (IFFALSE onFalse=stats)? IFCLOSE #if
| WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while | WHILEOPEN cond=stats WHILETRUE onTrue=stats WHILECLOSE #while
| LAMBDA IDENTIFIER+ ARROW expr #lambda
| variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call | variable PAROPEN (expr (LISTDELIM expr)*)? PARCLOSE #call
| variable #getVariable | variable #getVariable
| LITERAL10 #literalInteger | LITERAL10 #literalInteger

View File

@ -17,7 +17,6 @@ public class ArrayTest {
@Test @Test
public void correctArrayParsing() { public void correctArrayParsing() {
BoppiTests.parseFile("simpleArray.boppi"); BoppiTests.parseFile("simpleArray.boppi");
BoppiTests.log.forEach((l)->System.out.println(l.getMessage()));
assertThat(BoppiTests.log, empty()); assertThat(BoppiTests.log, empty());
} }

View File

@ -35,6 +35,21 @@ public class ConditionalTest {
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
} }
/**
* Wrong if-else and loop use
*/
@Test
public void wrongConditionalChecking() {
BoppiTests.checkString("if 5 then 0 fi");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("5 + if true then 3 fi");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("while 'a' do 1+1 od");
assertThat(BoppiTests.log, hasSize(1));
}
/** /**
* Correct evaluation of basic programs * Correct evaluation of basic programs
*/ */

View File

@ -8,6 +8,8 @@ import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import pp.s1184725.boppi.util.RegisterPool;
/** /**
* Test cases for the basic expression language. * Test cases for the basic expression language.
* *
@ -82,14 +84,16 @@ public class ExpressionTest {
public void correctExpressionGeneration() { public void correctExpressionGeneration() {
BoppiTests.compileAndRunFile("simpleExpression.boppi"); BoppiTests.compileAndRunFile("simpleExpression.boppi");
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("1", "1", "3", "A", "false")));
int n = 12; int n = RegisterPool.RECOMMENDED_REGISTER_COUNT+3;
String expression = StringUtils.repeat("1+(", n) + "1" + StringUtils.repeat(")", n); String expression = StringUtils.repeat("1+(", n) + "0" + StringUtils.repeat(")", n);
BoppiTests.withWarnings(() -> { BoppiTests.withWarnings(() -> {
BoppiTests.compileAndRunString("print(" + expression + ")", "" + n); BoppiTests.compileAndRunString("print(" + expression + ")", "" + n);
assertThat(BoppiTests.log, hasSize(1)); assertThat(BoppiTests.log, hasSize(1));
assertThat(BoppiTests.log.get(0).getLevel(), is(Level.WARNING)); assertThat(BoppiTests.log.get(0).getLevel(), is(Level.WARNING));
assertThat(BoppiTests.out, is(arrayContaining(Integer.toString(n))));
}); });
} }

View File

@ -106,7 +106,6 @@ public class ILOCAllocatorTest {
*/ */
@Test @Test
public void simpleMallocFree() { public void simpleMallocFree() {
// Simulator.DEBUG = true;
sim(malloc(11, obj1)); sim(malloc(11, obj1));
assertThat(vm.getInterrupt(), is(0)); assertThat(vm.getInterrupt(), is(0));
assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT))); assertThat(vm.load(FIRSTPTR), is(not(FIRSTSLOT)));

View File

@ -16,6 +16,12 @@ public class SimpleFunctionTest {
*/ */
@Test @Test
public void correctFunctionParsing() { public void correctFunctionParsing() {
BoppiTests.parseString("function constantProcedure() 0; 1");
assertThat(BoppiTests.log, is(empty()));
BoppiTests.parseString("function procedure(int a) a; 1");
assertThat(BoppiTests.log, is(empty()));
BoppiTests.parseString("function int id(int a) a; 1"); BoppiTests.parseString("function int id(int a) a; 1");
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
@ -40,9 +46,12 @@ public class SimpleFunctionTest {
*/ */
@Test @Test
public void wrongFunctionParsing() { public void wrongFunctionParsing() {
BoppiTests.parseString("function char add(int a, int b);"); BoppiTests.parseString("function char add(int a, int b); 'c'");
assertThat(BoppiTests.log, hasSize(1)); assertThat(BoppiTests.log, hasSize(1));
BoppiTests.parseString("function char add(a, b); 1");
assertThat(BoppiTests.log, is(not(empty())));
BoppiTests.parseString("function int add(int a, int b) a+b; add(4,)"); BoppiTests.parseString("function int add(int a, int b) a+b; add(4,)");
assertThat(BoppiTests.log, hasSize(1)); assertThat(BoppiTests.log, hasSize(1));
} }
@ -69,6 +78,9 @@ public class SimpleFunctionTest {
BoppiTests.checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}; 0"); BoppiTests.checkString("function int factorial(int n) {if (n > 1) then n*factorial(n-1) else 1 fi}; 0");
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
BoppiTests.checkString("var int a; a := 1; function int id(int a) a; 1");
assertThat(BoppiTests.log, is(empty()));
} }
/** /**
@ -76,6 +88,9 @@ public class SimpleFunctionTest {
*/ */
@Test @Test
public void wrongFunctionChecking() { public void wrongFunctionChecking() {
BoppiTests.checkString("var int add; add := 1; add(4, 2)");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)"); BoppiTests.checkString("function int add(int a, char b) a+b; print(add(4, 'T')+1)");
assertThat(BoppiTests.log, hasSize(1)); assertThat(BoppiTests.log, hasSize(1));
@ -84,6 +99,15 @@ public class SimpleFunctionTest {
BoppiTests.checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)"); BoppiTests.checkString("function int add(int a, int b) a+b; print(add(4, 'T')+1)");
assertThat(BoppiTests.log, hasSize(1)); assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("function int id(int a) a; print(id(4, 2)+1)");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("function nothing(int a) a; print(nothing(2))");
assertThat(BoppiTests.log, hasSize(1));
BoppiTests.checkString("function int add(int a, int b) a+b; print(add(4)+1)");
assertThat(BoppiTests.log, hasSize(1));
} }
/** /**
@ -104,6 +128,10 @@ public class SimpleFunctionTest {
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("1"))); assertThat(BoppiTests.out, is(arrayContaining("1")));
BoppiTests.compileAndRunString("var int a; a := 1; function int id(int a) a; print(id(4))");
assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("4")));
BoppiTests.compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)"); BoppiTests.compileAndRunString("function int add(int a, int b) a+b; print(add(4, 5)+1)");
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
assertThat(BoppiTests.out, is(arrayContaining("10"))); assertThat(BoppiTests.out, is(arrayContaining("10")));

View File

@ -126,7 +126,10 @@ public class SimpleVariableTest {
@Test @Test
public void correctVariableGeneration() { public void correctVariableGeneration() {
BoppiTests.compileAndRunFile("simpleVariable.boppi"); BoppiTests.compileAndRunFile("simpleVariable.boppi");
BoppiTests.log.forEach((l)->System.out.println(l.getMessage())); assertThat(BoppiTests.log, is(empty()));
BoppiTests.compileAndRunFile("simpleScope.boppi");
assertThat(BoppiTests.out, is(arrayContaining("9", "4", "true")));
assertThat(BoppiTests.log, is(empty())); assertThat(BoppiTests.log, is(empty()));
} }

View File

@ -28,7 +28,8 @@ function (int,int)->int logCalls((int,int)->int f) {
return return
}; };
add := logCalls(add); var add add_;
add_ := logCalls(add);
print(add(1,6), add(10,5)); print(add_(1,6), add_(10,5));
print(getCalls()); print(getCalls());

View File

@ -20,9 +20,10 @@ function int main1() {
return return
}; };
add := logCalls(add); var add add_;
add_ := logCalls(add);
print(add(1,6), add(10,5)); print(add_(1,6), add_(10,5));
print(getCalls()); print(getCalls());
}; };

View File

@ -2,13 +2,7 @@
var int n; var int n;
function int fib(int n) { var (int)->int fib;
if n < 2 then
1
else
fib(n-1)+fib(n-2)
fi
};
function fib memoize(fib f) { function fib memoize(fib f) {
var [50]int memo; var [50]int memo;
@ -33,7 +27,15 @@ function fib memoize(fib f) {
memoFib memoFib
}; };
fib := memoize(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_);
read(n); read(n);

View File

@ -32,4 +32,6 @@ myBool := {
99 + (myInt := 100); 99 + (myInt := 100);
}; };
otherInt > 3; otherInt > 3;
} };
print(otherInt, myInt, myBool);