check 'if' condition type, mark functions constant, improved tests
This commit is contained in:
parent
eae3c68b51
commit
68093f96e9
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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")));
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -32,4 +32,6 @@ myBool := {
|
||||||
99 + (myInt := 100);
|
99 + (myInt := 100);
|
||||||
};
|
};
|
||||||
otherInt > 3;
|
otherInt > 3;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
print(otherInt, myInt, myBool);
|
||||||
|
|
Loading…
Reference in New Issue