00001 package plp.functional2.expression;
00002
00003 import static plp.expressions1.util.ToStringProvider.listToString;
00004
00005 import java.util.HashMap;
00006 import java.util.List;
00007 import java.util.Map;
00008
00009 import plp.expressions1.util.Tipo;
00010 import plp.expressions2.expression.Expressao;
00011 import plp.expressions2.expression.Id;
00012 import plp.expressions2.expression.Valor;
00013 import plp.expressions2.memory.AmbienteCompilacao;
00014 import plp.expressions2.memory.AmbienteExecucao;
00015 import plp.expressions2.memory.VariavelJaDeclaradaException;
00016 import plp.expressions2.memory.VariavelNaoDeclaradaException;
00017 import plp.functional1.declaration.DeclaracaoFuncional;
00018 import plp.functional1.util.TipoPolimorfico;
00019 import plp.functional2.declaration.DecFuncao;
00020
00021 public class ExpDeclaracao implements Expressao {
00022
00023 List<? extends DeclaracaoFuncional> seqdecFuncional;
00024 Expressao expressao;
00025
00026 public ExpDeclaracao(List<? extends DeclaracaoFuncional> declaracoes,
00027 Expressao expressaoArg) {
00028 seqdecFuncional = declaracoes;
00029 expressao = expressaoArg;
00030 }
00031
00037 @Override
00038 public String toString() {
00039 return String.format("let %s in %s",
00040 listToString(seqdecFuncional, ","), expressao);
00041 }
00042
00043 public Valor avaliar(AmbienteExecucao ambiente)
00044 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00045 ambiente.incrementa();
00046
00047
00048
00049
00050 Map<Id, Valor> auxIdValor = new HashMap<Id, Valor>();
00051 Map<Id, ValorFuncao> auxIdValorFuncao = new HashMap<Id, ValorFuncao>();
00052
00053 resolveBindings(ambiente, auxIdValor, auxIdValorFuncao);
00054
00055 includeBindings(ambiente, auxIdValor, auxIdValorFuncao);
00056
00057 Valor vresult = expressao.avaliar(ambiente);
00058 ambiente.restaura();
00059 return vresult;
00060 }
00061
00062 private void includeBindings(AmbienteExecucao ambiente,
00063 Map<Id, Valor> auxIdValor, Map<Id, ValorFuncao> auxIdValorFuncao)
00064 throws VariavelJaDeclaradaException {
00065 for (Map.Entry<Id, Valor> idValor : auxIdValor.entrySet()) {
00066 ambiente.map(idValor.getKey(), idValor.getValue());
00067 }
00068
00069 for (Map.Entry<Id, ValorFuncao> idValorFuncao : auxIdValorFuncao
00070 .entrySet()) {
00071 ambiente.map(idValorFuncao.getKey(), idValorFuncao.getValue());
00072 }
00073
00074 }
00075
00076 private void resolveBindings(AmbienteExecucao ambiente,
00077 Map<Id, Valor> auxIdValor, Map<Id, ValorFuncao> auxIdValorFuncao)
00078 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00079
00080 for (DeclaracaoFuncional decFuncional : this.seqdecFuncional) {
00081 if (decFuncional.getAridade() == 0) {
00082 auxIdValor.put(decFuncional.getId(), decFuncional
00083 .getExpressao().avaliar(ambiente));
00084 } else {
00085 DecFuncao decFuncao = (DecFuncao) decFuncional;
00086 ValorFuncao valorFuncao = decFuncao.getFuncao();
00087 auxIdValorFuncao.put(decFuncional.getId(), valorFuncao);
00088 }
00089 }
00090 }
00091
00105 public boolean checaTipo(AmbienteCompilacao ambiente)
00106 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00107 ambiente.incrementa();
00108
00109 boolean result = false;
00110 try {
00111 result = checkTypeBindings(ambiente);
00112 if (result) {
00113 Map<Id, Tipo> resolvedTypes = resolveTypeBidings(ambiente);
00114 includeTypeBindings(ambiente, resolvedTypes);
00115 result = expressao.checaTipo(ambiente);
00116 }
00117 } finally {
00118 ambiente.restaura();
00119 }
00120 return result;
00121 }
00122
00123 private Map<Id, Tipo> resolveTypeBidings(AmbienteCompilacao ambiente)
00124 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00125 Map<Id, Tipo> resolvedTypes = new HashMap<Id, Tipo>();
00126
00127 for (DeclaracaoFuncional decFuncional : this.seqdecFuncional) {
00128 if (resolvedTypes.put(decFuncional.getId(), decFuncional
00129 .getTipo(ambiente)) != null)
00130 throw new VariavelJaDeclaradaException(decFuncional.getId());
00131 }
00132 return resolvedTypes;
00133 }
00134
00135 private boolean checkTypeBindings(AmbienteCompilacao ambiente)
00136 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00137 boolean result = true;
00138
00139 for (DeclaracaoFuncional decFuncional : this.seqdecFuncional) {
00140 if (!decFuncional.checaTipo(ambiente)) {
00141 ambiente.restaura();
00142 result = false;
00143 }
00144 }
00145 return result;
00146 }
00147
00148 private void includeTypeBindings(AmbienteCompilacao ambiente,
00149 Map<Id, Tipo> resolvedTypes) throws VariavelJaDeclaradaException {
00150 for (Id id : resolvedTypes.keySet()) {
00151 ambiente.map(id, resolvedTypes.get(id));
00152 }
00153 }
00154
00168 public Tipo getTipo(AmbienteCompilacao ambiente)
00169 throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
00170 ambiente.incrementa();
00171
00172 Tipo vresult = null;
00173
00174 for (DeclaracaoFuncional decFuncional : this.seqdecFuncional) {
00175 if (decFuncional.getAridade() == 0) {
00176 ambiente.map(decFuncional.getId(), decFuncional.getExpressao()
00177 .getTipo(ambiente));
00178 } else {
00179 DecFuncao decFuncao = (DecFuncao) decFuncional;
00180 Tipo tipo = decFuncao.getFuncao().getTipo(ambiente);
00181 if (tipo != TipoPolimorfico.CURINGA) {
00182 ambiente.map(decFuncional.getId(), tipo);
00183 }
00184 }
00185 }
00186 vresult = expressao.getTipo(ambiente);
00187 ambiente.restaura();
00188 return vresult;
00189 }
00190
00196 public List<? extends DeclaracaoFuncional> getSeqdecFuncional() {
00197 return seqdecFuncional;
00198 }
00199
00205 public Expressao getExpressao() {
00206 return expressao;
00207 }
00208
00209 }