Instructions

V prevajalnik dodajte pravilo, da se v nobenem izrazu (in s tem seveda v njegovih podizrazih) ne smeta hkrati pojaviti operatorja + in -.

Test

var x: int

fun main(): int =
	x = 1+2+(-2),
	x = 1+2-2

Out

Before

No error

After

Error

Code

/seman/TypeChecker.java

public class TypeChecker implements AST.FullVisitor<TYP.Type, TypeChecker.Info> {
    public static class Info {
        public AST.FunDefn parentFunDefn;
 
// --- ADDED: Track usage of plus and minus in expressions ---
        public boolean usedPlus = false;
        public boolean usedMinus = false;
 
        public Info() {
            parentFunDefn = null;
        }
    }
 
    // ... other code ...
 
    // ----- Statements -----
    @Override
    public TYP.Type visit(AST.AssignStmt assignStmt, Info info) {
// --- ADDED: Save and reset plus/minus usage before visiting sub-expressions ---
        boolean previousUsedPlus = info.usedPlus; info.usedPlus = false;
        boolean previousUsedMinus = info.usedMinus; info.usedMinus = false;
        assignStmt.dstExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
 
        info.usedPlus = false;
        info.usedMinus = false;
        assignStmt.srcExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
// --- END ADDED ---
 
        TYP.Type dstExprType = SemAn.ofType.get(assignStmt.dstExpr);
        TYP.Type srcExprType = SemAn.ofType.get(assignStmt.srcExpr);
 
        if (!typeEqu(dstExprType, srcExprType))
            throw new Report.Error(assignStmt, "TypeChecker error: Assignment types do not match");
 
        return null;
    }
 
    @Override
    public TYP.Type visit(AST.ReturnStmt returnStmt, Info info) {
// --- ADDED: Save and reset plus/minus usage before visiting sub-expressions ---
        boolean previousUsedPlus = info.usedPlus; info.usedPlus = false;
        boolean previousUsedMinus = info.usedMinus; info.usedMinus = false;
        returnStmt.retExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
// --- END ADDED ---
 
        if (info.parentFunDefn == null)
            throw new Report.Error(returnStmt, "TypeChecker error: Return statement not inside a function");
 
        TYP.Type retType = SemAn.ofType.get(returnStmt.retExpr);
        TYP.Type funType = SemAn.ofType.get(info.parentFunDefn.type);
 
        if (!typeEqu(retType, funType))
            throw new Report.Error(returnStmt, "TypeChecker error: Return type does not match function type");
 
        return null;
    }
 
    @Override
    public TYP.Type visit(AST.WhileStmt whileStmt, Info info) {
// --- ADDED: Save and reset plus/minus usage before visiting sub-expressions ---
        boolean previousUsedPlus = info.usedPlus; info.usedPlus = false;
        boolean previousUsedMinus = info.usedMinus; info.usedMinus = false;
        whileStmt.condExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
// --- END ADDED ---
 
        whileStmt.stmts.accept(this, info);
 
        TYP.Type condType = SemAn.ofType.get(whileStmt.condExpr);
        if (!typeEqu(condType, TYP.BoolType.type))
            throw new Report.Error(whileStmt, "TypeChecker error: While condition must be boolean");
 
        return null;
    }
 
    @Override
    public TYP.Type visit(AST.IfThenStmt ifThenStmt, Info info) {
// --- ADDED: Save and reset plus/minus usage before visiting sub-expressions ---
        boolean previousUsedPlus = info.usedPlus; info.usedPlus = false;
        boolean previousUsedMinus = info.usedMinus; info.usedMinus = false;
        ifThenStmt.condExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
// --- END ADDED ---
 
        ifThenStmt.thenStmt.accept(this, info);
 
        TYP.Type condType = SemAn.ofType.get(ifThenStmt.condExpr);
        if (!typeEqu(condType, TYP.BoolType.type))
            throw new Report.Error(ifThenStmt, "TypeChecker error: If condition must be boolean");
 
        return null;
    }
 
    @Override
    public TYP.Type visit(AST.IfThenElseStmt ifThenElseStmt, Info info) {
// --- ADDED: Save and reset plus/minus usage before visiting sub-expressions ---
        boolean previousUsedPlus = info.usedPlus; info.usedPlus = false;
        boolean previousUsedMinus = info.usedMinus; info.usedMinus = false;
        ifThenElseStmt.condExpr.accept(this, info);
        info.usedPlus = previousUsedPlus; info.usedMinus = previousUsedMinus;
// --- END ADDED ---
 
        ifThenElseStmt.thenStmt.accept(this, info);
        ifThenElseStmt.elseStmt.accept(this, info);
 
        TYP.Type condType = SemAn.ofType.get(ifThenElseStmt.condExpr);
        if (!typeEqu(condType, TYP.BoolType.type))
            throw new Report.Error(ifThenElseStmt, "TypeChecker error: If condition must be boolean");
 
        return null;
    }
 
    // ... other code ...
 
    @Override
    public TYP.Type visit(AST.PfxExpr pfxExpr, Info info) {
        TYP.Type subExprType = pfxExpr.subExpr.accept(this, info);
 
        if (pfxExpr.oper == AST.PfxExpr.Oper.ADD || pfxExpr.oper == AST.PfxExpr.Oper.SUB) {
            if (!typeEqu(subExprType, TYP.IntType.type))
                throw new Report.Error(pfxExpr, "TypeChecker error: Only integer expression is allowed here");
 
// --- ADDED: Track plus/minus usage and disallow both in same expression ---
            if (pfxExpr.oper == AST.PfxExpr.Oper.ADD) {
                info.usedPlus = true;
                if (info.usedMinus)
                    throw new Report.Error(pfxExpr, "TypeChecker error: Plus and minus not allowed in same expression");
            }
            else {
                info.usedMinus = true;
                if (info.usedPlus)
                    throw new Report.Error(pfxExpr, "TypeChecker error: Plus and minus not allowed in same expression");
            }
// --- END ADDED ---
 
            SemAn.ofType.put(pfxExpr, subExprType);
            SemAn.isConst.put(pfxExpr, SemAn.isConst.get(pfxExpr.subExpr));
        } else if (pfxExpr.oper == AST.PfxExpr.Oper.NOT) {
            // ... existing code ...
        }
        // ... existing code ...
    }
 
    // ... other code ...
 
    @Override
    public TYP.Type visit(AST.BinExpr binExpr, Info info) {
        // ... existing code ...
        if (binExpr.oper == AST.BinExpr.Oper.ADD || binExpr.oper == AST.BinExpr.Oper.SUB) {
            // ... existing code ...
 
// --- ADDED: Track plus/minus usage and disallow both in same expression ---
            if (binExpr.oper == AST.BinExpr.Oper.ADD) {
                info.usedPlus = true;
                if (info.usedMinus)
                    throw new Report.Error(binExpr, "TypeChecker error: Plus and minus not allowed in same expression");
            }
            else {
                info.usedMinus = true;
                if (info.usedPlus)
                    throw new Report.Error(binExpr, "TypeChecker error: Plus and minus not allowed in same expression");
            }
// --- END ADDED ---
 
            if (sndIntoFstCoercible)
                SemAn.ofType.put(binExpr, fstExprType);
            else SemAn.ofType.put(binExpr, sndExprType);
        }
        // ... existing code ...
    }
 
    // ... other code ...
}