Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adiciona a lista e alguns métodos #20

Merged
merged 1 commit into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gramatica/PortuscriptLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ NAO_BIT_A_BIT: '~';
DESLOC_ESQUERDA: '<<';
DESLOC_DIREITA: '>>';
PONTO: '.';
ABRE_COLCHETES: '[';
FECHA_COLCHETES: ']';

ID: (LETRAS | '_') (LETRAS | DIGITOS)*;

Expand Down
4 changes: 3 additions & 1 deletion gramatica/PortuscriptParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,6 @@ argumento: expressao;

atomo: ID | 'Verdadeiro' | 'Falso' | 'Nulo' | TEXTO+ | DIGITOS | tupla;

tupla: ABRE_CHAVES expressao VIRGULA (expressao VIRGULA?)* FECHA_CHAVES;
tupla: ABRE_CHAVES expressao VIRGULA (expressao VIRGULA?)* FECHA_CHAVES;

lista: ABRE_COLCHETES expressao (VIRGULA expressao)* FECHA_COLCHETES;
6 changes: 6 additions & 0 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ func (l *Lexer) ProximoToken() Token {
case "}":
l.avancar()
return Token{TokenFechaChaves, "}"}
case "[":
l.avancar()
return Token{TokenAbreColchetes, "["}
case "]":
l.avancar()
return Token{TokenFechaColchetes, "]"}
case "|":
l.avancar()
return Token{TokenBitABitOu, "|"}
Expand Down
2 changes: 2 additions & 0 deletions lexer/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const (
TokenVirgula // ,
TokenAbreChaves // {
TokenFechaChaves // }
TokenAbreColchetes // {
TokenFechaColchetes // }
TokenDoisPontos // :

// Reatribuicao
Expand Down
5 changes: 5 additions & 0 deletions parser/ast_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ type TuplaLiteral struct {
Elementos []BaseNode
}

type ListaLiteral struct {
Elementos []BaseNode
}

func (*Programa) isExpr() {}
func (*DeclVar) isExpr() {}
func (*Reatribuicao) isExpr() {}
Expand All @@ -136,3 +140,4 @@ func (*BlocoPara) isExpr() {}
func (*PareNode) isExpr() {}
func (*ContinueNode) isExpr() {}
func (*TuplaLiteral) isExpr() {}
func (*ListaLiteral) isExpr() {}
16 changes: 16 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,22 @@ func (p *Parser) parseAtomo() (BaseNode, error) {
literal.Elementos = append(literal.Elementos, exp)
}

p.avancar()
return literal, nil
case lexer.TokenAbreColchetes:
literal := &ListaLiteral{}

for p.token.Tipo != lexer.TokenFechaColchetes {
p.avancar()
exp, err := p.parseExpressao()

if err != nil {
return nil, err
}

literal.Elementos = append(literal.Elementos, exp)
}

p.avancar()
return literal, nil
}
Expand Down
2 changes: 2 additions & 0 deletions ptst/erros.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ var (
TipagemErro = TipoErro.NewTipo("TipagemErro", "Tipo de argumento inapropriado.")
NomeErro = TipoErro.NewTipo("NomeErro", "Erro de nome que não pode ser achado.")
ImportacaoErro = TipoErro.NewTipo("ImportacaoErro", "Não é possível encontrar o módulo ou símbolo nele")
ValorErro = TipoErro.NewTipo("ValorErro", "O valor é inapropriádo ou sua ocorrencia não existe")
IndiceErro = TipoErro.NewTipo("IndiceErro", "O indice está fora do range aceito")
FimIteracao = TipoErro.NewTipo("FimIteracao", "Sinaliza o fim da iteração quando `objeto.__proximo__() não retorna mais nada")

// Apenas para fins de controle, não são necessariamente erros
Expand Down
18 changes: 17 additions & 1 deletion ptst/interpretador.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func (i *Interpretador) visite(node parser.BaseNode) (Objeto, error) {
return i.visiteDecimalLiteral(node.(*parser.DecimalLiteral))
case *parser.TuplaLiteral:
return i.visiteTuplaLiteral(node.(*parser.TuplaLiteral))
case *parser.ListaLiteral:
return i.visiteListaLiteral(node.(*parser.ListaLiteral))
case *parser.OpBinaria:
return i.visiteOpBinaria(node.(*parser.OpBinaria))
case *parser.Identificador:
Expand Down Expand Up @@ -193,6 +195,20 @@ func (i *Interpretador) visiteTuplaLiteral(node *parser.TuplaLiteral) (Objeto, e
return tupla, nil
}

func (i *Interpretador) visiteListaLiteral(node *parser.ListaLiteral) (Objeto, error) {
lista := &Lista{}

for _, elemento := range node.Elementos {
item, err := i.visite(elemento)
if err != nil {
return nil, err
}

lista.Adiciona(item)
}
return lista, nil
}

func (i *Interpretador) visiteOpBinaria(node *parser.OpBinaria) (Objeto, error) {
esquerda, err := i.visite(node.Esq)

Expand Down Expand Up @@ -402,7 +418,7 @@ func (i *Interpretador) visiteBlocoPara(node *parser.BlocoPara) (Objeto, error)

return nil, err
}
}
}
}

func (i *Interpretador) visitePareNode(node *parser.PareNode) (Objeto, error) {
Expand Down
143 changes: 143 additions & 0 deletions ptst/lista.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package ptst

type Lista struct {
Itens Tupla
}

var TipoLista = TipoObjeto.NewTipo(
"Lista",
"Lista(obj) -> Lista",
)

func (l *Lista) Tipo() *Tipo {
return TipoLista
}

func (l *Lista) O__iter__() (Objeto, error) {
return NewIterador(l.Itens)
}

func (l *Lista) O__texto__() (Objeto, error) {
return l.Itens.GRepr("[", "]")
}

func (l *Lista) O__tamanho__() (Objeto, error) {
return l.Itens.O__tamanho__()
}

var _ I__iter__ = (*Lista)(nil)
var _ I__texto__ = (*Lista)(nil)
var _ I__tamanho__ = (*Lista)(nil)

func (l *Lista) Adiciona(item Objeto) (Objeto, error) {
l.Itens = append(l.Itens, item)
return nil, nil
}

func (l *Lista) Indice(obj Objeto) (Objeto, error) {
for indice, item := range l.Itens {
if ok, _ := Igual(item, obj); ok.(Booleano) {
return Inteiro(indice), nil
}
}

objTexto, err := NewTexto(obj)
if err != nil {
return nil, err
}

return nil, NewErroF(ValorErro, "O item '%s' não está na lista", objTexto)
}

func (l *Lista) Pop(indice Inteiro) (Objeto, error) {
tamanho, err := l.O__tamanho__()
if err != nil {
return nil, err
}

if indice > tamanho.(Inteiro) || indice < 0 {
return nil, NewErroF(IndiceErro, "O range é de %d indice(s), %d está fora dele", tamanho.(Inteiro), indice)
}

var removido Objeto
var novaTupla Tupla

for idx, item := range l.Itens {
if idx == int(indice) {
removido = item
continue
}

novaTupla = append(novaTupla, item)
}

l.Itens = novaTupla
return removido, nil
}

func init() {
TipoLista.Mapa["adiciona"] = NewMetodoOuPanic("adiciona", func(inst Objeto, args Tupla) (Objeto, error) {
if len(args) < 1 {
return nil, NewErroF(TipagemErro, "O método adiciona() esperava receber no mínimo 1 argumento, mas recebeu um total de %v", len(args))
}

inst.(*Lista).Adiciona(args[0])
return nil, nil
}, "O método recebe um objeto e adiciona ao fim da lista")

// TipoLista.Mapa["insere"] = NewMetodoOuPanic("insere", func(inst Objeto, args Tupla) (Objeto, error) {
// if len(args) < 2 {
// return nil, NewErroF(TipagemErro, "O método insere() esperava receber no mínimo 2 argumentos, mas recebeu um total de %v", len(args))
// }

// indice, objeto := args[0], args[1]

// return nil, nil
// }, "")

TipoLista.Mapa["extende"] = NewMetodoOuPanic("extende", func(inst Objeto, args Tupla) (Objeto, error) {
if len(args) < 1 {
return nil, NewErroF(TipagemErro, "O método extende() esperava receber no mínimo 1 argumento, mas recebeu um total de %v", len(args))
}

inst.(*Lista).Itens = append(inst.(*Lista).Itens, (args[0].(Tupla))...)
return nil, nil
}, "Adiciona os elementos da lista recebida ao fim da lista atual")

TipoLista.Mapa["remove"] = NewMetodoOuPanic("remove", func(inst Objeto, args Tupla) (Objeto, error) {
if len(args) < 1 {
return nil, NewErroF(TipagemErro, "O método remove() esperava receber no mínimo 1 argumento, mas recebeu um total de %v", len(args))
}

instancia := inst.(*Lista)
idx, err := instancia.Indice(args[0])
if err != nil {
return nil, err
}

return instancia.Pop(idx.(Inteiro))
}, "Remove um elemento da lista e o retorna, se existir")

TipoLista.Mapa["pop"] = NewMetodoOuPanic("pop", func(inst Objeto, args Tupla) (Objeto, error) {
idx := Inteiro(0)

if len(args) == 1 {
idx = args[0].(Inteiro)
}

return inst.(*Lista).Pop(idx)
}, "Remove um item da lista com base no seu índice")

TipoLista.Mapa["indice"] = NewMetodoOuPanic("indice", func(inst Objeto, args Tupla) (Objeto, error) {
if len(args) < 1 {
return nil, NewErroF(TipagemErro, "O método indice() esperava receber no mínimo 1 argumento, mas recebeu um total de %v", len(args))
}

return inst.(*Lista).Indice(args[0])
}, "Retorna o índice de um elemento se ele existir na lista")

TipoLista.Mapa["limpa"] = NewMetodoOuPanic("limpa", func(inst Objeto) (Objeto, error) {
inst.(*Lista).Itens = Tupla(nil)
return nil, nil
}, "Limpa completamente a lista")
}