Skip to content

Feat add symbol table visitor#31

Open
Pedro6508 wants to merge 15 commits into
devfrom
feat-add-symbol-table-visitor
Open

Feat add symbol table visitor#31
Pedro6508 wants to merge 15 commits into
devfrom
feat-add-symbol-table-visitor

Conversation

@Pedro6508

Copy link
Copy Markdown
Collaborator

Descrição

Closes #

Tipo de mudança

  • Bug fix (mudança não crítica que conserta uma issue)
  • New feature (mudança não crítica que adiciona uma nova feature)
  • Mudança crítica (Concerto ou uma feature que pode quebrar funcionalidades antigas)
  • Apenas mudança de documentação

Checklist:

  • Realizei uma revisão do meu código
  • Eu comentei meus códigos, particularmente nas aŕeas mais difíceis
  • Eu fiz as mudanças correspondentes na documentação
  • Minhas mudanças não geraram nenhum warning
  • Qualquer mudança pendente na dev branch já foi implementada nessa branch

@talDoFlemis talDoFlemis changed the base branch from main to dev April 7, 2024 20:07
@AllArgsConstructor
public class ClassDeclSimple extends ClassDecl {
private Identifier className;
public Identifier className;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utilize o getters e setters do lombok, não deixe todos os campos da AST publico

import org.example.ast.ClassDeclSimple
import org.example.ast2.org.example.visitor.MethodDeclListVisitor

class ClassDeclVisitor : SymbolVisitor<ClassDeclSimple>() {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Falta os casos de herança nas classes

import org.example.ast.VarDecl
import org.example.ast.VarDeclList

class VarDeclListVisitor : SymbolVisitor<VarDeclList>() {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Onde está os testes que comprovam que a sua implementação funciona na AST de verdade?


abstract class SymbolVisitor<T> {
var table : Table = Table()
abstract fun visit(entity: T): Either<Error, Table>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

É interessante ter uma coleção de erros para reportar ao usuário como o Heron falou na aula

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isso é bem tranquilo de mudar é só alterar de Either<Error, *> para EitherNel<Error, *>. Mas não quero mudar até fechar a implementação.

Comment on lines +17 to +50
object ClassDeclVisitor : SymbolVisitor<ClassDecl> {
private fun extractName(entity: ClassDecl): String =
when (entity) {
is ClassDeclSimple -> entity.className.s
is ClassDeclExtends -> entity.className.s
else -> throw IllegalArgumentException(
"ClassDeclVisitor: ClassDecl must be either ClassDeclSimple or ClassDeclExtends"
)
}

object ClassDeclSimpleVisitor : SymbolVisitor<ClassDeclSimple> {
override fun Table.visit(entity: ClassDeclSimple): Either<Error, Table> = either {
this@visit + Table(
ClassData(
name = extractName(entity),
fields = dispatch(entity.fields).bind(),
methods = dispatch(entity.methods).bind()
)
)
}
}

object ClassDeclExtendsVisitor : SymbolVisitor<ClassDeclExtends> {
override fun Table.visit(entity: ClassDeclExtends): Either<Error, Table> = either {
this@visit + Table(
ClassData(
name = extractName(entity),
fields = dispatch(entity.fields).bind(),
methods = dispatch(entity.methods).bind()
)
)
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Como você planeja resolver os simbolos de herança da super classe que a subclasse herda?

class Super {
   public int a;
}

class Sub extends Super {
}

Onde essa classe sub terá o valor a como padrão na implementação. Como você irá resolver os casos em que há redeclaração de variável e de métodos? E se essa redeclaração alterar o tipo como você resolve?

fields = Table(),
methods = Table(
MethodData(
name = entity.className.s,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

o nome do método é sempre main está na gramática
image

Comment on lines +63 to +82
@JvmInline
value class Error(val message: String)

interface SymbolVisitor<T> {
companion object {
fun <T> dispatch(entity: T, table: Table = Table()): Either<Error, Table> =
when (entity) {
is MainClass -> MainClassVisitor.run { table.visit(entity) }
is ClassDeclSimple -> ClassDeclVisitor.ClassDeclSimpleVisitor.run { table.visit(entity) }
is ClassDeclExtends -> ClassDeclVisitor.ClassDeclExtendsVisitor.run { table.visit(entity) }
is VarDecl -> VarDeclVisitor.run { table.visit(entity) }
is VarDeclList -> VarDeclListVisitor.run { table.visit(entity) }
is MethodDecl -> MethodDeclVisitor.run { table.visit(entity) }
is MethodDeclList -> MethodDeclListVisitor.run { table.visit(entity) }
is FormalList -> FormalsListVisitor.run { table.visit(entity) }
is Formal -> FormalsVisitor.run { table.visit(entity) }
is Program -> ProgramVisitor.run { table.visit(entity) }
else -> throw IllegalArgumentException("SymbolVisitor: Unknown entity type")
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uma das coisas que o Visitor Pattern busca resolver é exatamente esse monte de condicional para resolver que operação aplicar em determinada estrutura usando Double Dispatch.

Que ao invés disso:
image

A gente tem isso:
image

Tanto que toda estrutura que utiliza visitor o inicio das chamadas não é visitor.visit e sim struct.accept, porque a estrutura que injeta o algorítimo nela

Comment on lines +76 to +77
fields = dispatch(varDeclList).getOrElse { fail("Should not fail") },
methods = dispatch(methodDeclList).getOrElse { fail("Should not fail") }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não sei se eu entendi direito, mas você está aplicando seu algorítmo no resultado experado? Se sim, porque não usar o resultado esperado na mão, já que não seria um teste que a implementação é comparada com ela mesma

Comment on lines +11 to +62
//class ClassDeclVisitorTest {
// fun tearDown() {
// unmockkAll()
// }
//
//
// @Test
// fun `should visit class decl`(): Unit = ClassDeclVisitor.run {
// // Arrange
// val table = Table()
// val classDecl = ClassDecl.builder()
// .className(Identifier.builder().s("Main").build())
// .varDecls(VarDeclList.builder().build())
// .methodDecls(MethodDeclList.builder().build())
// .build()
// val expectedTable = Table(
// ClassData(
// name = "Main"
// )
// )
//
// // Act
// val result = table.visit(classDecl)
//
// // Assert
// assertThat(result).isEqualTo(expectedTable.right())
// }
//
// @Test
// fun `should visit class decl with error`(): Unit = ClassDeclVisitor.run {
// // Arrange
// val table = Table()
// val classDecl = ClassDecl.builder()
// .className(Identifier.builder().s("Main").build())
// .varDecls(VarDeclList.builder().build())
// .methodDecls(MethodDeclList.builder().build())
// .build()
// val expectedTable = Table(
// ClassData(
// name = "Main"
// )
// )
// val expectedError = Error("ClassDeclVisitor: ClassDecl must have a unique name")
//
// // Act
// val result = table.visit(classDecl)
//
// // Assert
// assertThat(result).isEqualTo(expectedTable.right())
// }
//
//}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remover dead code no teste

Comment on lines +70 to +96
fun `should visit program`(): Unit = ProgramVisitor.run {
// Arrange
val expectedMainTable = MainClassVisitorTest.defaultMainTable
val expectedClassTable = expectedMainTable + Table(
MainClassVisitorTest.defaultClassData.copy(
name = "otherClass"
)
)
val expectedFullTable = expectedClassTable + Table(
MainClassVisitorTest.defaultClassData,
MainClassVisitorTest.defaultClassData.copy(
name = "otherClass"
)
)
val table = Table()
val program = slot<Program>()
mockkObject(SymbolVisitor.Companion) {
every { dispatch(any(MainClass::class), table) } returns expectedMainTable.right()
every { dispatch(any(ClassDeclList::class), table) } returns expectedClassTable.right()

// Act
val result = dispatch(program, table)

// Assert
assertThat(result).isEqualTo(expectedFullTable.right())
}
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não entendi muito bem esse código, poderia explicar no zap depois?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

2 participants