package me.tomassetti.turin.compiler;
import me.tomassetti.bytecode_generation.BytecodeSequence;
import me.tomassetti.turin.parser.ast.FormalParameterNode;
import me.tomassetti.turin.parser.ast.Node;
import me.tomassetti.turin.symbols.FormalParameter;
import me.tomassetti.turin.symbols.Symbol;
import java.util.*;
/**
* An instance is created for each method.
* The list (and the assignations of indexes) are global for the whole methods
* but the names can be visible only inside inner blocks.
*/
public class LocalVarsSymbolTable {
private List<Symbol> values = new LinkedList<>();
private List<Block> blockOfDeckaration = new LinkedList<>();
private List<String> orderedNames = new LinkedList<>();
private int startIndex;
private LocalVarsSymbolTable parent;
private Block currentBlock = new Block(null);
private Map<String, BytecodeSequence> aliases = new HashMap<>();
public void recordAlias(String name, BytecodeSequence bs) {
aliases.put(name, bs);
}
public boolean hasAlias(String name) {
return aliases.containsKey(name);
}
public BytecodeSequence getAlias(String name) {
if (!hasAlias(name)) {
throw new IllegalArgumentException();
}
return aliases.get(name);
}
public void add(FormalParameter formalParameter) {
add(formalParameter.getName(), formalParameter);
}
// Each instance is equals just to itself, by design.
private class Block {
Block parent;
public Block(Block parent) {
this.parent = parent;
}
}
private LocalVarsSymbolTable(int startIndex, LocalVarsSymbolTable parent) {
this.startIndex = startIndex;
this.parent = parent;
}
public static LocalVarsSymbolTable forStaticMethod() {
// no space needed for "this"
return new LocalVarsSymbolTable(0, null);
}
public static LocalVarsSymbolTable forInstanceMethod() {
// space needed for "this"
return new LocalVarsSymbolTable(1, null);
}
/**
* Return the index in the symbol table.
*/
public int add(String name, Symbol value) {
values.add(value);
orderedNames.add(name);
blockOfDeckaration.add(currentBlock);
return orderedNames.size() - 1;
}
public Optional<Integer> findIndex(String name) {
return findIndexInBlock(name, currentBlock);
}
public Optional<Symbol> findDeclaration(String name) {
Optional<Integer> index = findIndex(name);
if (index.isPresent()) {
return Optional.of(values.get(index.get() - startIndex));
} else {
return Optional.empty();
}
}
private Optional<Integer> findIndexInBlock(String name, Block block) {
for (int i=0;i<orderedNames.size();i++) {
if (orderedNames.get(i).equals(name)) {
if (blockOfDeckaration.get(i).equals(block)) {
return Optional.of(i + startIndex);
}
}
}
if (block.parent == null) {
return Optional.empty();
} else {
return findIndexInBlock(name, block.parent);
}
}
public void enterBlock() {
Block newBlock = new Block(currentBlock);
currentBlock = newBlock;
}
public void exitBlock() {
if (currentBlock.parent == null) {
throw new IllegalStateException();
}
currentBlock = currentBlock.parent;
}
}