Logo Pastebin.fr
Pastebin

Retrouvez, créez et partagez vos snippets en temps réel.

and

package fr.ensimag.deca.tree;

import java.io.PrintStream;

import org.apache.commons.lang.Validate;

import fr.ensimag.deca.DecacCompiler;
import fr.ensimag.deca.context.ClassDefinition;
import fr.ensimag.deca.context.ContextualError;
import fr.ensimag.deca.context.VariableDefinition;
import fr.ensimag.deca.context.ExpDefinition;
import fr.ensimag.deca.context.MethodDefinition;
import fr.ensimag.deca.context.EnvironmentExp;
import fr.ensimag.deca.context.Signature;
import fr.ensimag.deca.context.Type;
import fr.ensimag.deca.tools.IndentPrintStream;
import fr.ensimag.deca.tools.SymbolTable.Symbol;
import fr.ensimag.ima.pseudocode.Label;
import fr.ensimag.ima.pseudocode.Register;
import fr.ensimag.ima.pseudocode.RegisterOffset;
import fr.ensimag.ima.pseudocode.ImmediateString;
import fr.ensimag.ima.pseudocode.instructions.ADDSP;
import fr.ensimag.ima.pseudocode.instructions.BOV;
import fr.ensimag.ima.pseudocode.instructions.RTS;
import fr.ensimag.ima.pseudocode.instructions.SUBSP;
import fr.ensimag.ima.pseudocode.instructions.TSTO;
import fr.ensimag.ima.pseudocode.instructions.WNL;
import fr.ensimag.ima.pseudocode.instructions.WSTR;
import fr.ensimag.ima.pseudocode.instructions.ERROR;

/**
 * Declaration of a method
 *
 * @author gl57
 * @date 01/01/2026
 */
public class DeclMethod extends AbstractDeclMethod {
    
    private final AbstractIdentifier returnType;
    private final AbstractIdentifier methodName;
    private final ListDeclParam params;
    private final MethodBody body; // null if ASM

    public DeclMethod(AbstractIdentifier returnType, AbstractIdentifier methodName, 
                      ListDeclParam params, MethodBody body) {
        Validate.notNull(returnType);
        Validate.notNull(methodName);
        Validate.notNull(params);
        this.returnType = returnType;
        this.methodName = methodName;
        this.params = params;
        this.body = body;
    }

    public AbstractIdentifier getReturnType() {
        return returnType;
    }

    public AbstractIdentifier getMethodName() {
        return methodName;
    }

    public ListDeclParam getParams() {
        return params;
    }

    public MethodBody getBody() {
        return body;
    }

    @Override
    protected void verifyDeclMethod(DecacCompiler compiler,
            ClassDefinition currentClass) throws ContextualError {

        Type typeDeRetour = returnType.verifyType(compiler);
        
        EnvironmentExp localEnv = new EnvironmentExp(null);
        Signature signature = getParams().verifyListParam(compiler, localEnv, currentClass);
        
        Symbol methodSymb = methodName.getName();
        EnvironmentExp environnementMembres = currentClass.getMembers();
        ExpDefinition existingDef = environnementMembres.get(methodSymb);
        
        if (existingDef != null) {
            if (!existingDef.isMethod()) {
                throw new ContextualError("Method '" + methodSymb + "' conflicts with non-method definition", methodName.getLocation());
            }
            
            MethodDefinition superMethod = existingDef.asMethodDefinition("", methodName.getLocation());
            Signature superSig = superMethod.getSignature();
            Type superReturnType = superMethod.getType();
            
            if (!signaturesEqual(signature, superSig)) {
                throw new ContextualError("Method '" + methodSymb + "' has different signature than superclass", methodName.getLocation());
            }
            
            if (!typeDeRetour.isSubTypeOf(superReturnType, compiler.environmentType)) {
                throw new ContextualError("Method '" + methodSymb + "' return type must be a subtype of superclass return type",methodName.getLocation());
            }
        }
        
        int methodIndex = currentClass.getNumberOfMethods();
        MethodDefinition methodDef = new MethodDefinition(typeDeRetour, getLocation(), signature, methodIndex);
        
        try {
            environnementMembres.declare(methodSymb, methodDef);
        } catch (EnvironmentExp.DoubleDefException e) {
            throw new ContextualError("Method '" + methodSymb + "' is already declared in this class", methodName.getLocation());
        // on décore le methodName avec la définition de la méthode
        }
        
        methodName.setDefinition(methodDef);
        methodName.setType(typeDeRetour);
        currentClass.incNumberOfMethods();
    }
    
    private boolean signaturesEqual(Signature sig1, Signature sig2) {
        if (sig1.size() != sig2.size()) {
            return false;
        }
        for (int i = 0; i < sig1.size(); i++) {
            if (!sig1.paramNumber(i).sameType(sig2.paramNumber(i))) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    protected void verifyMethodBody(DecacCompiler compiler,
            ClassDefinition currentClass) throws ContextualError {
        if (body == null) {
            // si il n'y a pas de body, on fait rien
            return;
        }

        // Même logique que pour verifyDeclMethod
        
        // on vérifie le type de retour
        Type typeDeRetour = returnType.verifyType(compiler);
        EnvironmentExp environnementMembres = currentClass.getMembers();
        
        // Création un nouvel environnement pour la méthode
        EnvironmentExp methodEnv = new EnvironmentExp(environnementMembres);
        for (DeclParam param : getParams().getList()) {
            Type paramType = param.getType().verifyType(compiler);
            // Pas possible d'avoir un paramètre void
            if (paramType.isVoid()) {
                throw new ContextualError("Parameter cannot be declared void", param.getType().getLocation());
            }
            // on crée une définition de variable pour le paramètre
            VariableDefinition paramDef = new VariableDefinition(paramType, param.getLocation());
            // on déclare le paramètre dans l'environnement de la méthode
            try {
                methodEnv.declare(param.getName().getName(), paramDef);
            } catch (EnvironmentExp.DoubleDefException e) {
                throw new ContextualError("Duplicate parameter: " + param.getName().getName(), param.getName().getLocation());
            }
            param.getName().setDefinition(paramDef);
        }
        
        body.verifyMethodBody(compiler, methodEnv, currentClass, typeDeRetour);
    }

    void codeGenMethod(DecacCompiler compiler, ClassDefinition currentClass) {
        MethodDefinition methodDef = methodName.getMethodDefinition();
        Label methodLabel = methodDef.getLabel();
        if (methodLabel == null) {
            methodLabel = new Label("code." + currentClass.getType().getName().getName()
                    + "." + methodName.getName().getName());
            methodDef.setLabel(methodLabel);
        }
        Label endLabel = new Label("fin." + currentClass.getType().getName().getName()
                + "." + methodName.getName().getName());

        compiler.addLabel(methodLabel);
        compiler.enterMethod(endLabel);

        int nVar = 0;
        if (body != null) {
            nVar = body.getDeclVariables().getList().size();
        }

        if (nVar > 0) {
            compiler.addInstruction(new TSTO(nVar));
            compiler.addInstruction(new BOV(new Label("stack_overflow_error")));
            compiler.addInstruction(new ADDSP(nVar));
        }

        int paramOffset = -3;
        for (DeclParam param : params.getList()) {
            VariableDefinition def = param.getName().getVariableDefinition();
            def.setOperand(new RegisterOffset(paramOffset, Register.LB));
            paramOffset--;
        }

        if (body != null) {
            body.codeGenMethodBody(compiler, currentClass, returnType.getType());
        }

        if (!returnType.getType().isVoid()) {
            compiler.addInstruction(new WSTR(new ImmediateString(
                    "Error: method " + currentClass.getType().getName().getName()
                            + "." + methodName.getName().getName() + " ended without return")));
            compiler.addInstruction(new WNL());
            compiler.addInstruction(new ERROR());
        }

        compiler.addLabel(endLabel);
        if (nVar > 0) {
            compiler.addInstruction(new SUBSP(nVar));
        }
        compiler.addInstruction(new RTS());
        compiler.exitMethod();
    }

    @Override
    public void decompile(IndentPrintStream s) {
        returnType.decompile(s);
        s.print(" ");
        methodName.decompile(s);
        s.print("(");
        params.decompile(s);
        s.print(") ");
        if (body != null) {
            body.decompile(s);
        } else {
            s.print("asm { ... }");
        }
    }

    @Override
    protected void iterChildren(TreeFunction f) {
        returnType.iter(f);
        methodName.iter(f);
        params.iter(f);
        if (body != null) {
            body.iter(f);
        }
    }

    @Override
    protected void prettyPrintChildren(PrintStream s, String prefix) {
        returnType.prettyPrint(s, prefix, false);
        methodName.prettyPrint(s, prefix, false);
        params.prettyPrint(s, prefix, false);
        if (body != null) {
            body.prettyPrint(s, prefix, true);
        }
    }
}

Créé il y a 3 semaines.

Rechercher un Pastebin

Aucun paste trouvé.