basic checker and checker test
This commit is contained in:
parent
c4f5c77fc4
commit
21dca82f4a
|
@ -0,0 +1,19 @@
|
||||||
|
package pp.s1184725.boppi;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeProperty;
|
||||||
|
|
||||||
|
import pp.iloc.model.Reg;
|
||||||
|
|
||||||
|
public class Annotations {
|
||||||
|
public ParseTreeProperty<Reg> registers;
|
||||||
|
public CachingSymbolTable<SimpleType> symbols;
|
||||||
|
public ParseTreeProperty<SimpleType> types;
|
||||||
|
public ParseTreeProperty<Variable<SimpleType>> variables;
|
||||||
|
|
||||||
|
public Annotations() {
|
||||||
|
registers = new ParseTreeProperty<>();
|
||||||
|
symbols = new CachingSymbolTable<>();
|
||||||
|
types = new ParseTreeProperty<>();
|
||||||
|
variables = new ParseTreeProperty<>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
package pp.s1184725.boppi;
|
||||||
|
|
||||||
|
import java.util.EmptyStackException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
|
||||||
|
import pp.s1184725.boppi.BasicParser.*;
|
||||||
|
|
||||||
|
public class BoppiBasicChecker extends BasicBaseVisitor<SimpleType> {
|
||||||
|
private Annotations an;
|
||||||
|
private Logger log;
|
||||||
|
|
||||||
|
public BoppiBasicChecker(Logger logger, Annotations annotations) {
|
||||||
|
an = annotations;
|
||||||
|
log = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visit(ParseTree tree) {
|
||||||
|
SimpleType type = super.visit(tree);
|
||||||
|
an.types.put(tree, type);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitAssign(AssignContext ctx) {
|
||||||
|
SimpleType expr = visit(ctx.singleExpr());
|
||||||
|
SimpleType var = visit(ctx.variable());
|
||||||
|
checkConstraint(expr, var, ctx);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitBool(BoolContext ctx) {
|
||||||
|
return SimpleType.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitBlock(BlockContext ctx) {
|
||||||
|
return inScope(() -> visit(ctx.expr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitChar(CharContext ctx) {
|
||||||
|
return SimpleType.CHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitExpr(ExprContext ctx) {
|
||||||
|
if (ctx.singleExpr(ctx.singleExpr().size() - 1) instanceof DeclareContext)
|
||||||
|
log.severe(getError(ctx, "Compound expression ends with declaration."));
|
||||||
|
|
||||||
|
return ctx.singleExpr().stream().map(this::visit).reduce((__, snd) -> snd).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitDeclare(DeclareContext ctx) {
|
||||||
|
try {
|
||||||
|
Variable<SimpleType> var = an.symbols.put(ctx.IDENTIFIER().getText(), visit(ctx.type()));
|
||||||
|
an.variables.put(ctx, var);
|
||||||
|
} catch (EmptyStackException e) {
|
||||||
|
log.severe(getError(ctx, "Declaring variable outside a program."));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.severe(getError(ctx, e.getMessage()));
|
||||||
|
}
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitIf(IfContext ctx) {
|
||||||
|
return inScope(() -> {
|
||||||
|
visit(ctx.cond);
|
||||||
|
if (ctx.onFalse != null) {
|
||||||
|
SimpleType trueType = inScope(() -> visit(ctx.onTrue));
|
||||||
|
SimpleType falseType = inScope(() -> visit(ctx.onFalse));
|
||||||
|
|
||||||
|
return (trueType.equals(falseType)) ? trueType : SimpleType.VOID;
|
||||||
|
} else {
|
||||||
|
inScope(() -> visit(ctx.onTrue));
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitInfix1(Infix1Context ctx) {
|
||||||
|
checkConstraint(visit(ctx.lhs), SimpleType.INT, ctx.lhs);
|
||||||
|
checkConstraint(visit(ctx.rhs), SimpleType.INT, ctx.rhs);
|
||||||
|
|
||||||
|
return SimpleType.INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitInfix2(Infix2Context ctx) {
|
||||||
|
checkConstraint(visit(ctx.lhs), SimpleType.INT, ctx.lhs);
|
||||||
|
checkConstraint(visit(ctx.rhs), SimpleType.INT, ctx.rhs);
|
||||||
|
|
||||||
|
return SimpleType.INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitInfix3(Infix3Context ctx) {
|
||||||
|
SimpleType lht = visit(ctx.lhs);
|
||||||
|
SimpleType rht = visit(ctx.rhs);
|
||||||
|
checkConstraint(lht, rht, ctx);
|
||||||
|
|
||||||
|
switch (ctx.op.getType()) {
|
||||||
|
case BasicLexer.LT:
|
||||||
|
case BasicLexer.LEQ:
|
||||||
|
case BasicLexer.GTE:
|
||||||
|
case BasicLexer.GT:
|
||||||
|
checkConstraint(lht, SimpleType.INT, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SimpleType.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitInfix4(Infix4Context ctx) {
|
||||||
|
checkConstraint(visit(ctx.lhs), SimpleType.BOOL, ctx.lhs);
|
||||||
|
checkConstraint(visit(ctx.rhs), SimpleType.BOOL, ctx.rhs);
|
||||||
|
|
||||||
|
return SimpleType.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitInfix5(Infix5Context ctx) {
|
||||||
|
checkConstraint(visit(ctx.lhs), SimpleType.BOOL, ctx.lhs);
|
||||||
|
checkConstraint(visit(ctx.rhs), SimpleType.BOOL, ctx.rhs);
|
||||||
|
|
||||||
|
return SimpleType.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitNumber(NumberContext ctx) {
|
||||||
|
return SimpleType.INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitParens(ParensContext ctx) {
|
||||||
|
return visit(ctx.expr());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitPrefix1(Prefix1Context ctx) {
|
||||||
|
SimpleType type = visit(ctx.singleExpr());
|
||||||
|
|
||||||
|
switch (ctx.op.getType()) {
|
||||||
|
case BasicLexer.NOT:
|
||||||
|
checkConstraint(type, SimpleType.BOOL, ctx.singleExpr());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BasicLexer.PLUS:
|
||||||
|
case BasicLexer.MINUS:
|
||||||
|
checkConstraint(type, SimpleType.INT, ctx.singleExpr());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitProgram(ProgramContext ctx) {
|
||||||
|
inScope(() -> super.visitProgram(ctx));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitRead(ReadContext ctx) {
|
||||||
|
if (ctx.variable().size() == 1) {
|
||||||
|
return visit(ctx.variable(0));
|
||||||
|
} else {
|
||||||
|
ctx.variable().forEach(this::visit);
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitType(TypeContext ctx) {
|
||||||
|
if (ctx.variable() != null)
|
||||||
|
return visit(ctx.variable());
|
||||||
|
else
|
||||||
|
return SimpleType.fromToken(ctx.staticType.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitVar(VarContext ctx) {
|
||||||
|
return visit(ctx.variable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitVariable(VariableContext ctx) {
|
||||||
|
try {
|
||||||
|
Variable<SimpleType> var = an.symbols.get(ctx.getText());
|
||||||
|
an.variables.put(ctx, var);
|
||||||
|
return var.getType();
|
||||||
|
} catch (EmptyStackException e) {
|
||||||
|
log.severe(getError(ctx, "Using variable outside a program."));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.severe(getError(ctx, e.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitWhile(WhileContext ctx) {
|
||||||
|
return inScope(() -> {
|
||||||
|
checkConstraint(visit(ctx.cond), SimpleType.BOOL, ctx.cond);
|
||||||
|
inScope(() -> visit(ctx.onTrue));
|
||||||
|
return SimpleType.VOID;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleType visitWrite(WriteContext ctx) {
|
||||||
|
if (ctx.expr().size() == 1) {
|
||||||
|
SimpleType type = visit(ctx.expr(0));
|
||||||
|
if (SimpleType.VOID.equals(type))
|
||||||
|
log.severe(getError(ctx, "Cannot print argument of type %s.", type));
|
||||||
|
|
||||||
|
return type;
|
||||||
|
} else {
|
||||||
|
ctx.expr().stream().map(this::visit).forEach((type) -> {
|
||||||
|
if (SimpleType.VOID.equals(type))
|
||||||
|
log.severe(getError(ctx, "Cannot print argument of type %s.", type));
|
||||||
|
});
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkConstraint(SimpleType type1, SimpleType type2, ParserRuleContext node) {
|
||||||
|
if (!type2.equals(type1))
|
||||||
|
log.severe(getError(node, "Could not match type %s with type %s.", type1.toString(), type2.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to correctly open a scope, run some code and close the
|
||||||
|
* scope. {@code} must take no arguments and must return a value.
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* the code to execute within the scope
|
||||||
|
* @return the result of {@code}
|
||||||
|
*/
|
||||||
|
protected <T> T inScope(Supplier<T> code) {
|
||||||
|
an.symbols.openScope();
|
||||||
|
T result = code.get();
|
||||||
|
an.symbols.closeScope();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an error message for a given parse tree node.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* the parse tree node at which the error occurred
|
||||||
|
* @param message
|
||||||
|
* the error message
|
||||||
|
* @param args
|
||||||
|
* arguments for the message, see {@link String#format}
|
||||||
|
*/
|
||||||
|
protected String getError(ParserRuleContext node, String message, Object... args) {
|
||||||
|
int line = node.getStart().getLine();
|
||||||
|
int column = node.getStart().getCharPositionInLine();
|
||||||
|
return String.format("Line %d:%d - %s", line, column, String.format(message, args));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package pp.s1184725.boppi;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import pp.iloc.eval.Machine;
|
||||||
|
|
||||||
|
public class CachingSymbolTable<T> {
|
||||||
|
protected Stack<Map<String,Variable<T>>> symbolMapStack;
|
||||||
|
protected Stack<Integer> offsets;
|
||||||
|
protected Map<String,Variable<T>> symbolCache;
|
||||||
|
protected int offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty symbol table with no open scope.
|
||||||
|
*/
|
||||||
|
public CachingSymbolTable() {
|
||||||
|
symbolMapStack = new Stack<>();
|
||||||
|
symbolCache = new HashMap<>();
|
||||||
|
offsets = new Stack<>();
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a lexical scope.
|
||||||
|
*/
|
||||||
|
public void openScope() {
|
||||||
|
symbolMapStack.push(new HashMap<>());
|
||||||
|
offsets.push(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes a lexical scope, removing all definitions within this scope.
|
||||||
|
* @throws EmptyStackException if no scope is open
|
||||||
|
*/
|
||||||
|
public void closeScope() throws EmptyStackException {
|
||||||
|
Map<String,Variable<T>> deletions = symbolMapStack.pop();
|
||||||
|
for (String identifier : deletions.keySet()) {
|
||||||
|
Optional<Variable<T>> maybeType = symbolMapStack.stream().filter((map) -> map.containsKey(identifier)).map((map) -> map.get(identifier)).reduce((__, snd) -> snd);
|
||||||
|
maybeType.ifPresent((var) -> symbolCache.replace(identifier, var));
|
||||||
|
if (!maybeType.isPresent())
|
||||||
|
symbolCache.remove(identifier);
|
||||||
|
}
|
||||||
|
offset = offsets.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates an identifier with a certain type in the current lexical scope.
|
||||||
|
* @param id the name of the identifier
|
||||||
|
* @param type the type of the identifier
|
||||||
|
* @return the type of the identifier
|
||||||
|
* @throws Exception if the identifier is declared in the current scope already
|
||||||
|
* @throws EmptyStackException if no scope is open
|
||||||
|
*/
|
||||||
|
public Variable<T> put(String id, T type) throws Exception, EmptyStackException {
|
||||||
|
if (symbolMapStack.peek().containsKey(id))
|
||||||
|
throw new Exception(String.format("Identifier '%s' already declared in this scope.", id));
|
||||||
|
|
||||||
|
Variable<T> var = new Variable<>(type, offset);
|
||||||
|
offset += Machine.INT_SIZE;
|
||||||
|
symbolMapStack.peek().put(id, var);
|
||||||
|
symbolCache.put(id, var);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given identifier is defined.
|
||||||
|
* @param id the name of the identifier
|
||||||
|
* @return true if the identifier has a defined type
|
||||||
|
* @throws EmptyStackException if no scope is open
|
||||||
|
*/
|
||||||
|
public boolean has(String id) throws EmptyStackException {
|
||||||
|
if (symbolMapStack.isEmpty())
|
||||||
|
throw new EmptyStackException();
|
||||||
|
|
||||||
|
return symbolCache.containsKey(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the type of an identifier, if any.
|
||||||
|
* @param id the name of the identifier
|
||||||
|
* @return the type of the identifier
|
||||||
|
* @throws Exception if the identifier is not defined
|
||||||
|
* @throws EmptyStackException if no scope is open
|
||||||
|
*/
|
||||||
|
public Variable<T> get(String id) throws Exception, EmptyStackException {
|
||||||
|
if (!this.has(id))
|
||||||
|
throw new Exception(String.format("Identifier '%s' is undefined.", id));
|
||||||
|
|
||||||
|
return symbolCache.get(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package pp.s1184725.boppi;
|
||||||
|
|
||||||
|
public enum SimpleType {
|
||||||
|
INT, CHAR, BOOL, VOID;
|
||||||
|
|
||||||
|
public static SimpleType fromToken(int token) {
|
||||||
|
switch (token) {
|
||||||
|
case BasicLexer.INTTYPE:
|
||||||
|
return SimpleType.INT;
|
||||||
|
|
||||||
|
case BasicLexer.CHARTYPE:
|
||||||
|
return SimpleType.CHAR;
|
||||||
|
|
||||||
|
case BasicLexer.BOOLTYPE:
|
||||||
|
return SimpleType.BOOL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SimpleType.VOID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package pp.s1184725.boppi;
|
||||||
|
|
||||||
|
public class Variable<T> {
|
||||||
|
private final T type;
|
||||||
|
private final int offset;
|
||||||
|
|
||||||
|
public Variable(T type, int offset) {
|
||||||
|
this.type = type;
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return type.toString()+" @ "+offset;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
package pp.s1184725.boppi.test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import pp.s1184725.boppi.Annotations;
|
||||||
|
import pp.s1184725.boppi.BasicParser;
|
||||||
|
import pp.s1184725.boppi.BasicParserHelper;
|
||||||
|
import pp.s1184725.boppi.BoppiBasicChecker;
|
||||||
|
|
||||||
|
public class CheckerTest {
|
||||||
|
static final Path directory = Paths.get("src/pp/s1184725/boppi/test/parsing/");
|
||||||
|
private List<LogRecord> log;
|
||||||
|
|
||||||
|
static private List<LogRecord> checkAndGetLog(String code) {
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
Pair<BasicParser, List<LogRecord>> pair = BasicParserHelper.getParserWithLog(code, logger);
|
||||||
|
new BoppiBasicChecker(logger, new Annotations()).visit(pair.getLeft().program());
|
||||||
|
return pair.getRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
static private List<LogRecord> checkAndGetLog(Path code) throws IOException {
|
||||||
|
Logger logger = Logger.getAnonymousLogger();
|
||||||
|
Pair<BasicParser, List<LogRecord>> pair = BasicParserHelper.getParserWithLog(code, logger);
|
||||||
|
new BoppiBasicChecker(logger, new Annotations()).visit(pair.getLeft().program());
|
||||||
|
return pair.getRight();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void debug() {
|
||||||
|
log.forEach(entry -> System.out.println(entry.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void correctExpressionTest() throws Exception {
|
||||||
|
log = checkAndGetLog(directory.resolve("simpleExpression.boppi"));
|
||||||
|
assertThat(log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wrongExpressionTest() {
|
||||||
|
log = checkAndGetLog("+true");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("5 || true");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("6 + 'c'");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("4 + print(5, 6)");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("print(print(3, 5))");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void correctVariableTest() throws Exception {
|
||||||
|
log = checkAndGetLog(directory.resolve("simpleVariable.boppi"));
|
||||||
|
assertThat(log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wrongVariableTest() {
|
||||||
|
log = checkAndGetLog("var bool name; name := 5");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("undefinedName");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("var undefinedType name; 1");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("var bool endsWithDeclaration;");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("var bool var1; var var1 var2; var2 := 'c' ");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void correctScopeTest() throws Exception {
|
||||||
|
log = checkAndGetLog(directory.resolve("simpleScope.boppi"));
|
||||||
|
assertThat(log, empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wrongScopeTest() {
|
||||||
|
log = checkAndGetLog("var bool var1; var bool var1; 1");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("var bool var1; var char var1; 1");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
|
||||||
|
log = checkAndGetLog("{ var int var1; var1 := 4}; var int var2; var1");
|
||||||
|
assertThat(log, hasSize(1));
|
||||||
|
assertThat(log.get(0).getLevel(), is(Level.SEVERE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void correctConditionalTest() throws Exception {
|
||||||
|
log = checkAndGetLog(directory.resolve("if.boppi"));
|
||||||
|
assertThat(log, empty());
|
||||||
|
|
||||||
|
log = checkAndGetLog(directory.resolve("while.boppi"));
|
||||||
|
assertThat(log, empty());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue