Skip to content

Commit

Permalink
merge: Merge pull request #22 from natanfeitosa/feat/importacoes
Browse files Browse the repository at this point in the history
feat: Adiciona importação de nomes
  • Loading branch information
natanfeitosa authored Jan 2, 2024
2 parents 4b3a9a9 + a87026e commit 5529234
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 62 deletions.
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/natanfeitosa/portuscript/parser"
"github.com/natanfeitosa/portuscript/playground"
"github.com/natanfeitosa/portuscript/ptst"
_ "github.com/natanfeitosa/portuscript/stdlib/embutidos"
_ "github.com/natanfeitosa/portuscript/stdlib"
"github.com/spf13/cobra"
)

Expand Down
7 changes: 7 additions & 0 deletions parser/ast_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ type ListaLiteral struct {
Elementos []BaseNode
}

// FIXME: adicionar suporte a importação com *
type ImporteDe struct {
Caminho *TextoLiteral
Nomes []string
}

func (*Programa) isExpr() {}
func (*DeclVar) isExpr() {}
func (*Reatribuicao) isExpr() {}
Expand All @@ -141,3 +147,4 @@ func (*PareNode) isExpr() {}
func (*ContinueNode) isExpr() {}
func (*TuplaLiteral) isExpr() {}
func (*ListaLiteral) isExpr() {}
func (*ImporteDe) isExpr() {}
94 changes: 67 additions & 27 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ func (p *Parser) parseDeclaracao() (BaseNode, error) {
}

// FIXME: adicionar importaçao
if val == "de" {
return p.parseImporteDe()
}

if val == "func" {
return p.parseFuncao()
Expand Down Expand Up @@ -128,6 +131,43 @@ func (p *Parser) parseDeclaracao() (BaseNode, error) {
return p.parseExpressao()
}

func (p *Parser) parseImporteDe() (*ImporteDe, error) {
p.avancar()
if p.token.Tipo != lexer.TokenTexto {
return nil, fmt.Errorf("Era esperado um texto após a palavra chave 'de'")
}

decl := &ImporteDe{Caminho: &TextoLiteral{p.token.Valor}}
p.avancar()

if err := p.consume("importe"); err != nil {
return nil, err
}

for {
// FIXME: adicionar suporte a importação com *
token := p.token

if token.Tipo == lexer.TokenIdentificador && !IsKeyword(token.Valor) {
p.avancar()
decl.Nomes = append(decl.Nomes, token.Valor)
}

if p.token.Tipo == lexer.TokenVirgula {
p.avancar()
continue
}

break
}

if err := p.consume(";"); err != nil {
return nil, err
}

return decl, nil
}

func (p *Parser) parseBlocoPara() (*BlocoPara, error) {
p.consume("para")
if err := p.consume("("); err != nil {
Expand All @@ -154,7 +194,7 @@ func (p *Parser) parseBlocoPara() (*BlocoPara, error) {
if err != nil {
return nil, err
}

return &BlocoPara{Identificador: id, Iterador: iter, Corpo: corpo}, nil
}

Expand Down Expand Up @@ -202,6 +242,32 @@ func (p *Parser) parseExpressaoSe() (*ExpressaoSe, error) {
return expressaoSe, nil
}

func (p *Parser) parseEnquanto() (*Enquanto, error) {
if err := p.consume("enquanto"); err != nil {
return nil, err
}

if err := p.consume("("); err != nil {
return nil, err
}

condicao, err := p.parseExpressao()
if err != nil {
return nil, err
}

if err := p.consume(")"); err != nil {
return nil, err
}

corpo, err := p.parseBloco()
if err != nil {
return nil, err
}

return &Enquanto{Condicao: condicao, Corpo: corpo}, nil
}

func (p *Parser) parseRetorne() (*RetorneNode, error) {
if err := p.consume("retorne"); err != nil {
return nil, err
Expand Down Expand Up @@ -779,29 +845,3 @@ func (p *Parser) parseAtomo() (BaseNode, error) {
// fmt.Printf("%t", p.token)
return nil, fmt.Errorf("O token '%v' não é reconhecido.", p.token.Valor)
}

func (p *Parser) parseEnquanto() (*Enquanto, error) {
if err := p.consume("enquanto"); err != nil {
return nil, err
}

if err := p.consume("("); err != nil {
return nil, err
}

condicao, err := p.parseExpressao()
if err != nil {
return nil, err
}

if err := p.consume(")"); err != nil {
return nil, err
}

corpo, err := p.parseBloco()
if err != nil {
return nil, err
}

return &Enquanto{Condicao: condicao, Corpo: corpo}, nil
}
4 changes: 4 additions & 0 deletions playground/playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func Inicializa(version, datetime, commit string) {
}

ast, err := stringParaAst(codigo)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}

interpretador := &ptst.Interpretador{
Ast: ast,
Expand Down
73 changes: 61 additions & 12 deletions ptst/contexto.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,39 @@ package ptst

import (
"strings"
"sync"
)

type Contexto struct {
Pai *Contexto // O contexto anterior (pai), se aplicavel
Caminho Texto // O caminho (path) do arquivo em execução
Locais *TabelaSimbolos // Variaveis e Constantes Locais
Globais *TabelaSimbolos // Variaveis e Constantes Globais
Modulos *TabelaModulos
Pai *Contexto // O contexto anterior (pai), se aplicavel
Caminho Texto // O caminho (path) do arquivo em execução
Locais *TabelaSimbolos // Variaveis e Constantes Locais
Globais *TabelaSimbolos // Variaveis e Constantes Globais
Modulos *TabelaModulos
waitgroup sync.WaitGroup
once sync.Once
fechado bool
// ErroAtual *Erro
}

func NewContexto(caminho Texto) *Contexto {
context := &Contexto{Caminho: caminho}
context.Globais = NewTabelaSimbolos()
context.Locais = NewTabelaSimbolos()
context.Globais = NewTabelaSimbolos()
context.Modulos = NewTabelaModulos()
context.fechado = false
return context
}

func NewContextoI(i *Interpretador) *Contexto {
contexto := NewContexto(i.Caminho)
i.Contexto = contexto
return contexto
}

func (c *Contexto) NewContexto() *Contexto {
context := &Contexto{
Pai: c,
Caminho: c.Caminho,
Locais: NewTabelaSimbolos(),
Globais: NewTabelaSimbolos(),
}
context := NewContexto(c.Caminho)
context.Pai = c
return context
}

Expand Down Expand Up @@ -90,3 +98,44 @@ func (c *Contexto) ObterSimbolo(nome string) (simbolo *Simbolo, err error) {
func (c *Contexto) ExcluirSimbolo(nome string) error {
return c.Locais.ExcluirSimbolo(nome)
}

func (c *Contexto) ObterModulo(nome string) (Objeto, error) {
return c.Modulos.ObterModulo(nome)
}

func (c *Contexto) InicializarModulo(implementacao *ModuloImpl) (Objeto, error) {
if err := c.adicionarTrabalho(); err != nil {
return nil, err
}
defer c.encerrarTrabalho()
// FIXME: adicionar a lógica para compilação e cache de módulos definidos do lado ptst da história

modulo, err := c.Modulos.NewModulo(c, implementacao)
if err != nil {
return nil, err
}

return modulo, nil
}

func (c *Contexto) adicionarTrabalho() error {
if c.fechado {
err := NewErro(RuntimeErro, Texto("Contexto já fechado"))
err.Contexto = c
return err
}

c.waitgroup.Add(1)
return nil
}

func (c *Contexto) encerrarTrabalho() {
c.waitgroup.Done()
}

func (c *Contexto) Terminar() {
c.once.Do(func () {
c.waitgroup.Wait()
c.fechado = true
})
}
1 change: 1 addition & 0 deletions ptst/erros.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var (
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")
RuntimeErro = TipoErro.NewTipo("RuntimeErro", "Erro no ambiente de execução")
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
25 changes: 25 additions & 0 deletions ptst/importe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ptst

func MaquinarioImporteModulo(ctx *Contexto, nome string) (Objeto, error) {
if modulo, err := ctx.ObterModulo(nome); err == nil {
return modulo, nil
}

if impl := ObtemImplModulo(nome); impl != nil {
return ctx.InicializarModulo(impl)
}

// FIXME: adicionar lógica para aquisição e inicialização de métodos "locais"

return nil, NewErroF(ImportacaoErro, "Não foi possível achar o módulo '%s', talvez seja um módulo local que ainda não é suportado", nome)
}

func MultiImporteModulo(ctx *Contexto, nomes ...string) error {
for _, nome := range nomes {
if _, err := MaquinarioImporteModulo(ctx, nome); err != nil {
return err
}
}

return nil
}
25 changes: 25 additions & 0 deletions ptst/interpretador.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ func (i *Interpretador) visite(node parser.BaseNode) (Objeto, error) {
return i.visitePareNode(node.(*parser.PareNode))
case *parser.ContinueNode:
return i.visiteContinueNode(node.(*parser.ContinueNode))
case *parser.ImporteDe:
return i.visiteImporteDe(node.(*parser.ImporteDe))
}

return nil, nil
Expand Down Expand Up @@ -455,6 +457,29 @@ func (i *Interpretador) visiteContinueNode(node *parser.ContinueNode) (Objeto, e
return nil, NewErro(ErroContinue, Nulo)
}

func (i *Interpretador) visiteImporteDe(node *parser.ImporteDe) (Objeto, error) {
caminho, err := i.visiteTextoLiteral(node.Caminho)
if err != nil {
return nil, err
}

modulo, err := MaquinarioImporteModulo(i.Contexto, string(caminho.(Texto)))
if err != nil {
return nil, err
}

for _, nome := range node.Nomes {
obj, err := ObtemItemS(modulo, nome)
if err != nil {
return nil, err
}

i.Contexto.DefinirSimboloLocal(NewVarSimbolo(nome, obj))
}

return nil, nil
}

func (i *Interpretador) criarErro(tipo *Tipo, args Objeto) error {
erro := NewErro(tipo, args)
erro.Contexto = i.Contexto
Expand Down
4 changes: 4 additions & 0 deletions ptst/mapa.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ var TipoMapa = NewTipo(
"Objeto chave/valor",
)

func NewMapaVazio() Mapa {
return make(Mapa)
}

func (m Mapa) Tipo() *Tipo {
return TipoMapa
}
Loading

0 comments on commit 5529234

Please sign in to comment.