Skip to content

Commit ef653ee

Browse files
committed
adiciona atribuicao se nulo e null coalescing
1 parent b1621de commit ef653ee

13 files changed

Lines changed: 239 additions & 17 deletions
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package li1.plp.expressions2.expression;
2+
3+
import li1.plp.expressions1.util.Tipo;
4+
import li1.plp.expressions1.util.TipoPrimitivo;
5+
import li1.plp.expressions1.util.TipoOptional;
6+
import li1.plp.expressions2.memory.AmbienteCompilacao;
7+
import li1.plp.expressions2.memory.AmbienteExecucao;
8+
import li1.plp.expressions2.memory.VariavelJaDeclaradaException;
9+
import li1.plp.expressions2.memory.VariavelNaoDeclaradaException;
10+
11+
public class ExpNullCoalescing extends ExpBinaria {
12+
13+
public ExpNullCoalescing(Expressao esq, Expressao dir) {
14+
super(esq, dir, "??");
15+
}
16+
17+
@Override
18+
public Valor avaliar(AmbienteExecucao amb) throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
19+
Valor valorEsq = getEsq().avaliar(amb);
20+
21+
// Se o valor da expressão da esquerda for nulo, retorna o valor da expressão da direita
22+
if (valorEsq instanceof ValorNulo) {
23+
return getDir().avaliar(amb);
24+
}
25+
return valorEsq;
26+
}
27+
28+
@Override
29+
protected boolean checaTipoElementoTerminal(AmbienteCompilacao ambiente)
30+
throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
31+
Tipo tipoEsq = getEsq().getTipo(ambiente);
32+
Tipo tipoDir = getDir().getTipo(ambiente);
33+
34+
// Se a expressão da esquerda for do tipo nulo, a expressão da direita deve ser válida
35+
if (tipoEsq.getNome().equals("NULO")) {
36+
return tipoDir.eValido();
37+
}
38+
39+
if (tipoEsq instanceof TipoOptional) {
40+
Tipo base = ((TipoOptional) tipoEsq).getBaseType();
41+
42+
// Se a base do tipo opcional for nula, o resultado é válido se a expressão da direita for válida
43+
if (base == null || base.getNome().equals("NULO")) {
44+
return tipoDir.eValido();
45+
}
46+
47+
// Se a base do tipo opcional for diferente de nulo, o resultado é válido se a base for igual ao tipo da expressão da direita
48+
return base.getNome().equals(tipoDir.getNome());
49+
}
50+
51+
// Se a expressão da esquerda não for nula nem opcional, os tipos devem ser iguais
52+
return tipoEsq.eIgual(tipoDir);
53+
}
54+
55+
@Override
56+
public Tipo getTipo(AmbienteCompilacao ambiente) throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
57+
Tipo tipoEsq = getEsq().getTipo(ambiente);
58+
Tipo tipoDir = getDir().getTipo(ambiente);
59+
60+
if (tipoEsq instanceof TipoOptional) {
61+
Tipo base = ((TipoOptional) tipoEsq).getBaseType();
62+
if (base != null && !base.getNome().equals("NULO")) {
63+
return base;
64+
}
65+
}
66+
67+
// Se a expressão da esquerda for do tipo nulo, o tipo resultante é o tipo da expressão da direita
68+
return tipoDir;
69+
}
70+
71+
@Override
72+
public ExpBinaria clone() {
73+
return new ExpNullCoalescing(getEsq().clone(), getDir().clone());
74+
}
75+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package li1.plp.imperative1.command;
2+
3+
import li1.plp.expressions2.expression.Expressao;
4+
import li1.plp.expressions2.expression.Id;
5+
import li1.plp.expressions2.expression.ValorNulo;
6+
import li1.plp.expressions2.memory.VariavelJaDeclaradaException;
7+
import li1.plp.expressions2.memory.VariavelNaoDeclaradaException;
8+
import li1.plp.imperative1.memory.AmbienteCompilacaoImperativa;
9+
import li1.plp.imperative1.memory.AmbienteExecucaoImperativa;
10+
11+
public class AtribuicaoSeNulo implements Comando {
12+
13+
private Id id;
14+
private Expressao expressao;
15+
16+
public AtribuicaoSeNulo(Id id, Expressao expressao) {
17+
this.id = id;
18+
this.expressao = expressao;
19+
}
20+
21+
public AmbienteExecucaoImperativa executar(
22+
AmbienteExecucaoImperativa ambiente)
23+
throws VariavelJaDeclaradaException, VariavelNaoDeclaradaException {
24+
// só atribui se o valor atual for nulo
25+
if (ambiente.get(id) instanceof ValorNulo) {
26+
ambiente.changeValor(id, expressao.avaliar(ambiente));
27+
}
28+
return ambiente;
29+
}
30+
31+
public boolean checaTipo(AmbienteCompilacaoImperativa ambiente)
32+
throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException {
33+
boolean isExpNull = expressao.getTipo(ambiente).eIgual(li1.plp.expressions1.util.TipoPrimitivo.NULO);
34+
boolean isIdOptional = id.getTipo(ambiente) instanceof li1.plp.expressions1.util.TipoOptional;
35+
36+
if (isExpNull && !isIdOptional) {
37+
return false;
38+
}
39+
if (isExpNull && isIdOptional) {
40+
return expressao.checaTipo(ambiente);
41+
}
42+
43+
boolean ok = expressao.checaTipo(ambiente)
44+
&& id.getTipo(ambiente).eIgual(expressao.getTipo(ambiente));
45+
46+
if (!ok) {
47+
System.out.println("Atribuicao Null-Aware falhou o checaTipo! id type: " + id.getTipo(ambiente).getNome() + ", exp type: " + expressao.getTipo(ambiente).getNome());
48+
}
49+
return ok;
50+
}
51+
}

Imperativa1/src/li1/plp/imperative1/parser/Imperative1.jj

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ TOKEN : /* OPERATORS */
253253
| < REM: "%" >
254254
}
255255

256+
TOKEN : /* NOVO: NULL-AWARE OPERATORS */
257+
{
258+
< NULL_COALESCING: "??" >
259+
| < NULL_AWARE_ASSIGN: "?:=" >
260+
}
256261

257262
Programa Input() :
258263
{
@@ -652,6 +657,8 @@ Expressao PExpressao() :
652657
(
653658
LOOKAHEAD (PExpBase() <HOOK>)
654659
retorno = PExpTernaria()
660+
| LOOKAHEAD (PExpBase() <NULL_COALESCING>)
661+
retorno = PExpNullCoalescing()
655662
|
656663
retorno = PExpBase()
657664
)
@@ -660,6 +667,18 @@ Expressao PExpressao() :
660667
}
661668
}
662669

670+
ExpNullCoalescing PExpNullCoalescing() :
671+
{
672+
Expressao esq;
673+
Expressao dir;
674+
}
675+
{
676+
esq = PExpBase()
677+
<NULL_COALESCING>
678+
dir = PExpressao()
679+
{return new ExpNullCoalescing(esq, dir);}
680+
}
681+
663682
/* ADICIONADO OU MODIFICADO DA Imperativa1 PARA A Imperativa2 */
664683

665684
Comando PComandoSimples() :
@@ -669,6 +688,7 @@ Comando PComandoSimples() :
669688
{
670689
(
671690
retorno = PSkip()
691+
| LOOKAHEAD(PId() <NULL_AWARE_ASSIGN>) retorno = PAtribuicaoSeNulo()
672692
| retorno = PAtribuicao()
673693
| retorno = PComandoDeclaracao()
674694
| retorno = PWhile()
@@ -681,6 +701,16 @@ Comando PComandoSimples() :
681701
}
682702
}
683703

704+
AtribuicaoSeNulo PAtribuicaoSeNulo() :
705+
{
706+
Id id;
707+
Expressao exp;
708+
}
709+
{
710+
id = PId() <NULL_AWARE_ASSIGN> exp = PExpressao()
711+
{ return new AtribuicaoSeNulo(id, exp); }
712+
}
713+
684714
ComandoDeclaracao PComandoDeclaracao() :
685715
{
686716
Declaracao dec;

README.md

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Para rodar todos os testes automatizados da pasta `Testes` e visualizar os resul
3232

3333
# Escopo
3434

35-
Esse projeto tem como objetivo adicionar à [Linguagem Imperativa 1](https://augustosampaio.github.io/PLP/linguagens/imperativa1) o operador Null, a capacidade de Null safety, e operadores presentes em linguagens modernas que estão relacionados ao conceito de Null ("??", "!", "??="), além do operador ternário.
35+
Esse projeto tem como objetivo adicionar à [Linguagem Imperativa 1](https://augustosampaio.github.io/PLP/linguagens/imperativa1) o operador Null, a capacidade de Null safety, e operadores presentes em linguagens modernas que estão relacionados ao conceito de Null ("??", "!", "?:="), além do operador ternário.
3636

3737
Abaixo temos o que será implementado pela linguagem em mais detalhes:
3838

@@ -79,19 +79,18 @@ Abaixo temos o que será implementado pela linguagem em mais detalhes:
7979
```
8080

8181

82-
- [ ] **Null coalescing:** Operador binário ("??") que retorna o lado direito da operação caso o operador seja null, ou o esquerdo caso não seja null. Valor "default".
82+
- [x] **Null coalescing:** Operador binário ("??") que retorna o lado direito da operação caso o operador seja null, ou o esquerdo caso não seja null. Valor "default".
8383

8484
Exemplo:
8585
```java
86-
{ var optional y = 2 ;
87-
{ var x = y ?? 3 ;
88-
write(x)
89-
}
86+
{
87+
var optional y = null,
88+
var x = y ?? 5;
89+
write(x)
9090
}
91-
// y pode ser null (nesse caso tem um valor)
92-
// Caso y seja null, x recebe 3
93-
// Caso não, x recebe y, que é 2
94-
// x vale 2
91+
// y pode ser null (nesse caso é null)
92+
// x é o valor de y caso y não seja null, ou 5 caso y seja null
93+
// x vale 5
9594
```
9695

9796
- [x] **Operador Ternário:** Operador "? :" que atua como um if-then-else.
@@ -132,17 +131,18 @@ Abaixo temos o que será implementado pela linguagem em mais detalhes:
132131
// x é o valor de y (aqui tomado como não-nulo) + 2
133132
// erro de execução por tentar acessar um valor que é nulo
134133
```
135-
- [ ] **Operador de atribuição Se Nulo (Null-Aware Assignment Operator):** operador binário ("??=") que atribui um valor ao lado esquerdo se, e somente se, esse valor for nulo. Na prática, seria um *shadowing* condicional.
134+
- [x] **Operador de atribuição Se Nulo (Null-Aware Assignment Operator):** operador binário ("?:=") que atribui um valor ao lado esquerdo se, e somente se, esse valor for nulo. Na prática, seria um *shadowing* condicional.
136135

137136
Exemplo:
138137
```java
139-
{ var optional y = null ;
140-
y ??= 5 ;
141-
y ??= 10 ;
142-
write(y)
138+
{
139+
var optional y = null;
140+
y ?:= 5;
141+
y ?:= 10;
142+
write(y)
143143
}
144144
// Declaramos uma variável como possivelmente nula
145-
// Atribuímos 5 a ela, já que ela é nula
145+
// Atribuímos a ela o valor 5, já que ela é nula
146146
// Como a variável agora tem um valor (5), ela não recebe 10
147147
// y vale 5
148148
```
@@ -164,7 +164,7 @@ Skip ::=
164164
165165
Atribuicao ::= Id “:=” Expressao
166166
167-
AtribuicaoSeNulo := Id "??=" Expressao
167+
AtribuicaoSeNulo := Id "?:=" Expressao
168168
169169
Expressao ::= Valor
170170
| ExpUnaria
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
expect: Erro de tipo
2+
3+
{
4+
var optional y = 3;
5+
y ?:= true;
6+
y ?:= false;
7+
write(y)
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
expect: 3
2+
3+
{
4+
var optional y = 3;
5+
y ?:= 5;
6+
y ?:= 10;
7+
write(y)
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
expect: 5
2+
3+
{
4+
var optional y = null;
5+
y ?:= 5;
6+
y ?:= 10;
7+
write(y)
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
expect: Erro de tipo
2+
3+
{
4+
var optional y = true,
5+
var x = y ?? 5;
6+
write(x)
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
expect: 2
2+
3+
{
4+
var y = 2,
5+
var x = y ?? 5;
6+
write(x)
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
expect: 3
2+
3+
{
4+
var optional y = 3,
5+
var x = y ?? 5;
6+
write(x)
7+
}

0 commit comments

Comments
 (0)