// Path: src/main/java/com/pidanic/saral/scope/Scope.java
// public class Scope {
// 
//     private static final LocalVariable EMPTY = new LocalVariable("empty", BuiltInType.BOOLEAN, true);
// 
//     private List<LocalVariable> localVariables;
//     private List<Function> functions;
//     private String className;
// 
//     public Scope(String className) {
//         localVariables = new ArrayList<>();
//         functions = new ArrayList<>();
//         this.className = className;
//     }
// 
//     public Scope(Scope scope) {
//         localVariables = new ArrayList<>(scope.localVariables);
//         functions = new ArrayList<>(scope.functions);
//         className = scope.className;
//     }
// 
//     public List<LocalVariable> getLocalVariables() {
//         return Collections.unmodifiableList(localVariables);
//     }
// 
//     public void addLocalVariable(LocalVariable localVariable) {
//         localVariables.add(localVariable);
//         if(localVariable.type() == BuiltInType.LONG || localVariable.type() == BuiltInType.DOUBLE) {
//             localVariables.add(EMPTY);
//         }
//     }
// 
//     public boolean existsLocalVariable(String variableName) {
//         return localVariables.stream().anyMatch(variable -> variable.name().equals(variableName));
//     }
// 
//     public Optional<LocalVariable> getLocalVariable(String varName) {
//         return localVariables.stream()
//                 .filter(variable -> variable.name().equals(varName))
//                 .findFirst();
//     }
// 
//     public int getLocalVariableIndex(String varName) {
//         return localVariables.stream().map(LocalVariable::name).collect(Collectors.toList()).indexOf(varName);
//     }
// 
//     public Optional<Function> getFunction(String functionName) {
//         return functions.stream().filter(proc -> proc.getName().equals(functionName))
//                 .findFirst();
//     }
// 
//     public String getClassName() {
//         return className;
//     }
// 
//     public void addFunction(Function function) {
//         this.functions.add(function);
//     }
// 
//     public LocalVariable initializeLocalVariableAtIndex(int index) {
//         LocalVariable localVariable = this.localVariables.get(index);
//         LocalVariable initializedLocalVar = localVariable.initialize();
//         this.localVariables.set(index, initializedLocalVar);
//         return initializedLocalVar;
//     }
// 
//     public LocalVariable initializeLocalVariable(String name) {
//         LocalVariable localVariable = getLocalVariable(name).get();
//         int index = getLocalVariableIndex(name);
//         LocalVariable initializedLocalVar = localVariable.initialize();
//         this.localVariables.set(index, initializedLocalVar);
//         return initializedLocalVar;
//     }
// 
//     public int localVariablesCount() {
//         return localVariables.size();
//     }
// }
// 
// Path: src/main/java/com/pidanic/saral/util/FunctionHelper.java
// public final class FunctionHelper {
// 
//     public static List<Argument> parseFunctionArguments(SaralParser.ArglistContext arglistContext, Scope scope) {
//         List<Argument> arguments = new ArrayList<>();
//         for(int i = 0; i < arglistContext.ID().size(); i++) {
//             String argName = arglistContext.ID(i).getText();
//             SaralParser.TypeContext typeContext = arglistContext.type(i);
//             Type argType;
//             if(typeContext.typeBasic() != null) {
//                 String argTypeName = typeContext.typeBasic().getText();
//                 argType = TypeResolver.getFromTypeName(argTypeName);
//             } else {
//                 argType = TypeResolver.getArrayTypeFromTypeName(typeContext.typeArray().typeBasic().getText());
//             }
//             LocalVariable var = new LocalVariable(argName, argType, true);
//             if(scope.existsLocalVariable(var.name())) {
//                 throw new VariableNameAlreadyExists(scope, var.name());
//             }
//             scope.addLocalVariable(var);
//             arguments.add(new Argument(argName, argType));
//         }
//         return arguments;
//     }
// }
// 
// Path: src/main/java/com/pidanic/saral/util/StatementsHelper.java
// public final class StatementsHelper {
//     public static List<Statement> parseStatements(SaralParser.StatementsContext statementsContext, Scope scope) {
//         List<Statement> allStatements = statementsContext.statement().stream().map(stmtCtx -> {
//             SaralParser.Block_statementContext block = stmtCtx.block_statement();
//             SaralParser.Simple_statementContext simpleStmt = stmtCtx.simple_statement();
//             Statement val;
//             if(block != null) {
//                 val = block.accept(new BlockStatementVisitor(scope));
//             } else {
//                 val = simpleStmt.accept(new SimpleStatementVisitor(scope));
//             }
//             return val;
//         }).collect(Collectors.toList());
// 
//         return allStatements;
//     }
// }


import com.pidanic.saral.domain.*;
import com.pidanic.saral.domain.block.*;
import com.pidanic.saral.grammar.SaralBaseVisitor;
import com.pidanic.saral.grammar.SaralParser;
import com.pidanic.saral.scope.Scope;
import com.pidanic.saral.util.FunctionHelper;
import com.pidanic.saral.util.StatementsHelper;
import java.util.Collections;
import java.util.List;
package com.pidanic.saral.visitor;



public class ProcedureVisitor extends SaralBaseVisitor<Procedure> {

    private Scope scope;

    public ProcedureVisitor(Scope scope) {
        this.scope = new Scope(scope);
    }

    @Override
    public Procedure visitProc_definition(SaralParser.Proc_definitionContext ctx) {
        String procedureName = ctx.ID().getText();

// Path: src/main/java/com/pidanic/saral/scope/Scope.java
// public class Scope {
// 
//     private static final LocalVariable EMPTY = new LocalVariable("empty", BuiltInType.BOOLEAN, true);
// 
//     private List<LocalVariable> localVariables;
//     private List<Function> functions;
//     private String className;
// 
//     public Scope(String className) {
//         localVariables = new ArrayList<>();
//         functions = new ArrayList<>();
//         this.className = className;
//     }
// 
//     public Scope(Scope scope) {
//         localVariables = new ArrayList<>(scope.localVariables);
//         functions = new ArrayList<>(scope.functions);
//         className = scope.className;
//     }
// 
//     public List<LocalVariable> getLocalVariables() {
//         return Collections.unmodifiableList(localVariables);
//     }
// 
//     public void addLocalVariable(LocalVariable localVariable) {
//         localVariables.add(localVariable);
//         if(localVariable.type() == BuiltInType.LONG || localVariable.type() == BuiltInType.DOUBLE) {
//             localVariables.add(EMPTY);
//         }
//     }
// 
//     public boolean existsLocalVariable(String variableName) {
//         return localVariables.stream().anyMatch(variable -> variable.name().equals(variableName));
//     }
// 
//     public Optional<LocalVariable> getLocalVariable(String varName) {
//         return localVariables.stream()
//                 .filter(variable -> variable.name().equals(varName))
//                 .findFirst();
//     }
// 
//     public int getLocalVariableIndex(String varName) {
//         return localVariables.stream().map(LocalVariable::name).collect(Collectors.toList()).indexOf(varName);
//     }
// 
//     public Optional<Function> getFunction(String functionName) {
//         return functions.stream().filter(proc -> proc.getName().equals(functionName))
//                 .findFirst();
//     }
// 
//     public String getClassName() {
//         return className;
//     }
// 
//     public void addFunction(Function function) {
//         this.functions.add(function);
//     }
// 
//     public LocalVariable initializeLocalVariableAtIndex(int index) {
//         LocalVariable localVariable = this.localVariables.get(index);
//         LocalVariable initializedLocalVar = localVariable.initialize();
//         this.localVariables.set(index, initializedLocalVar);
//         return initializedLocalVar;
//     }
// 
//     public LocalVariable initializeLocalVariable(String name) {
//         LocalVariable localVariable = getLocalVariable(name).get();
//         int index = getLocalVariableIndex(name);
//         LocalVariable initializedLocalVar = localVariable.initialize();
//         this.localVariables.set(index, initializedLocalVar);
//         return initializedLocalVar;
//     }
// 
//     public int localVariablesCount() {
//         return localVariables.size();
//     }
// }
// 
// Path: src/main/java/com/pidanic/saral/util/FunctionHelper.java
// public final class FunctionHelper {
// 
//     public static List<Argument> parseFunctionArguments(SaralParser.ArglistContext arglistContext, Scope scope) {
//         List<Argument> arguments = new ArrayList<>();
//         for(int i = 0; i < arglistContext.ID().size(); i++) {
//             String argName = arglistContext.ID(i).getText();
//             SaralParser.TypeContext typeContext = arglistContext.type(i);
//             Type argType;
//             if(typeContext.typeBasic() != null) {
//                 String argTypeName = typeContext.typeBasic().getText();
//                 argType = TypeResolver.getFromTypeName(argTypeName);
//             } else {
//                 argType = TypeResolver.getArrayTypeFromTypeName(typeContext.typeArray().typeBasic().getText());
//             }
//             LocalVariable var = new LocalVariable(argName, argType, true);
//             if(scope.existsLocalVariable(var.name())) {
//                 throw new VariableNameAlreadyExists(scope, var.name());
//             }
//             scope.addLocalVariable(var);
//             arguments.add(new Argument(argName, argType));
//         }
//         return arguments;
//     }
// }
// 
// Path: src/main/java/com/pidanic/saral/util/StatementsHelper.java
// public final class StatementsHelper {
//     public static List<Statement> parseStatements(SaralParser.StatementsContext statementsContext, Scope scope) {
//         List<Statement> allStatements = statementsContext.statement().stream().map(stmtCtx -> {
//             SaralParser.Block_statementContext block = stmtCtx.block_statement();
//             SaralParser.Simple_statementContext simpleStmt = stmtCtx.simple_statement();
//             Statement val;
//             if(block != null) {
//                 val = block.accept(new BlockStatementVisitor(scope));
//             } else {
//                 val = simpleStmt.accept(new SimpleStatementVisitor(scope));
//             }
//             return val;
//         }).collect(Collectors.toList());
// 
//         return allStatements;
//     }
// }


// Path: src/main/java/com/pidanic/saral/visitor/ProcedureVisitor.java
import com.pidanic.saral.domain.*;
import com.pidanic.saral.domain.block.*;
import com.pidanic.saral.grammar.SaralBaseVisitor;
import com.pidanic.saral.grammar.SaralParser;
import com.pidanic.saral.scope.Scope;
import com.pidanic.saral.util.FunctionHelper;
import com.pidanic.saral.util.StatementsHelper;
import java.util.Collections;
import java.util.List;

package com.pidanic.saral.visitor;



public class ProcedureVisitor extends SaralBaseVisitor<Procedure> {

    private Scope scope;

    public ProcedureVisitor(Scope scope) {
        this.scope = new Scope(scope);
    }

    @Override
    public Procedure visitProc_definition(SaralParser.Proc_definitionContext ctx) {
        String procedureName = ctx.ID().getText();

        List<Argument> arguments = FunctionHelper.parseFunctionArguments(ctx.arglist(), scope);