-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Task for code transpilation, so models can transpile Go code to Java …
…and back Closes #201
- Loading branch information
1 parent
9f2e248
commit c21e9ef
Showing
11 changed files
with
895 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package task | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
pkgerrors "github.com/pkg/errors" | ||
"github.com/symflower/eval-dev-quality/evaluate/metrics" | ||
"github.com/symflower/eval-dev-quality/language" | ||
"github.com/symflower/eval-dev-quality/language/golang" | ||
"github.com/symflower/eval-dev-quality/language/java" | ||
"github.com/symflower/eval-dev-quality/log" | ||
"github.com/symflower/eval-dev-quality/model" | ||
evaltask "github.com/symflower/eval-dev-quality/task" | ||
) | ||
|
||
// TaskTranspile holds the transpilation task. | ||
type TaskTranspile struct{} | ||
|
||
// TaskArgumentsTranspile holds extra arguments to be used in a query prompt. | ||
type TaskArgumentsTranspile struct { | ||
// SourceLanguage holds the source language for transpilation. | ||
SourceLanguage language.Language | ||
// StubFilePath holds the path for the file containing just the function signature of the language we are transpiling to. | ||
StubFilePath string | ||
} | ||
|
||
var _ evaltask.Task = (*TaskTranspile)(nil) | ||
|
||
// Identifier returns the transpilation task identifier. | ||
func (t *TaskTranspile) Identifier() evaltask.Identifier { | ||
return IdentifierTranspile | ||
} | ||
|
||
// Run transpiles code between Go and Java and runs predefined tests to check if the transpilation was successful. | ||
func (t *TaskTranspile) Run(ctx evaltask.Context) (repositoryAssessment map[evaltask.Identifier]metrics.Assessments, problems []error, err error) { | ||
modelCapability, ok := ctx.Model.(model.CapabilityTranspile) | ||
if !ok { | ||
return nil, nil, pkgerrors.Wrap(evaltask.ErrTaskUnsupportedByModel, fmt.Sprintf("%q does not support %q", ctx.Model.ID(), string(t.Identifier()))) | ||
} | ||
|
||
taskLogger, err := newTaskLogger(ctx, t) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
defer func() { | ||
taskLogger.finalize(problems) | ||
}() | ||
|
||
var packagePaths []string | ||
files, err := os.ReadDir(ctx.Repository.DataPath()) | ||
if err != nil { | ||
return nil, nil, pkgerrors.WithStack(err) | ||
} | ||
for _, file := range files { | ||
if file.IsDir() && !strings.HasPrefix(file.Name(), ".") { // Ignore hidden directories. | ||
packagePaths = append(packagePaths, filepath.Join(ctx.Repository.DataPath(), file.Name())) | ||
} | ||
} | ||
|
||
modelAssessments := metrics.NewAssessments() | ||
for _, packagePath := range packagePaths { | ||
if err := ctx.Repository.Reset(ctx.Logger); err != nil { | ||
ctx.Logger.Panicf("ERROR: unable to reset temporary repository path: %s", err) | ||
} | ||
|
||
var sourceLanguage language.Language | ||
if _, ok := ctx.Language.(*golang.Language); ok { | ||
sourceLanguage = &java.Language{} | ||
} else { | ||
sourceLanguage = &golang.Language{} | ||
} | ||
|
||
sourceFilePath, stubFilePath, err := t.unpackTranspilerPackage(ctx, taskLogger.Logger, sourceLanguage, packagePath) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
modelContext := model.Context{ | ||
Language: ctx.Language, | ||
|
||
RepositoryPath: packagePath, | ||
FilePath: sourceFilePath, | ||
|
||
Arguments: &TaskArgumentsTranspile{ | ||
SourceLanguage: sourceLanguage, | ||
StubFilePath: stubFilePath, | ||
}, | ||
|
||
Logger: taskLogger.Logger, | ||
} | ||
assessments, err := modelCapability.Transpile(modelContext) | ||
if err != nil { | ||
problems = append(problems, pkgerrors.WithMessage(err, sourceFilePath)) | ||
|
||
continue | ||
} | ||
if assessments[metrics.AssessmentKeyProcessingTime] == 0 { | ||
return nil, nil, pkgerrors.Errorf("no model response time measurement present for %q at repository %q", ctx.Model.ID(), ctx.Repository.Name()) | ||
} | ||
modelAssessments.Add(assessments) | ||
modelAssessments.Award(metrics.AssessmentKeyResponseNoError) | ||
|
||
coverage, ps, err := ctx.Language.Execute(taskLogger.Logger, packagePath) | ||
problems = append(problems, ps...) | ||
if err != nil { | ||
problems = append(problems, pkgerrors.WithMessage(err, sourceFilePath)) | ||
|
||
continue | ||
} | ||
taskLogger.Printf("Executes tests with %d coverage objects", coverage) | ||
modelAssessments.Award(metrics.AssessmentKeyFilesExecuted) | ||
modelAssessments.AwardPoints(metrics.AssessmentKeyCoverage, coverage) | ||
} | ||
|
||
repositoryAssessment = map[evaltask.Identifier]metrics.Assessments{ | ||
IdentifierTranspile: modelAssessments, | ||
} | ||
|
||
return repositoryAssessment, problems, nil | ||
} | ||
|
||
// unpackTranspilerPackage checks if the testdata repository for the transpilation task is well-formed and returns the path to the implementation file and also the path to the file that holds the stub. | ||
func (t *TaskTranspile) unpackTranspilerPackage(ctx evaltask.Context, fileLogger *log.Logger, sourceLanguage language.Language, packagePath string) (sourceFilePath string, stubFilePath string, err error) { | ||
// Check if the package path has a directory called "implementation" with a source file in the language to transpile from. | ||
files, err := sourceLanguage.Files(fileLogger, filepath.Join(packagePath, "implementation")) | ||
if err != nil { | ||
return "", "", pkgerrors.WithStack(err) | ||
} else if len(files) != 1 { | ||
return "", "", pkgerrors.Errorf("package %q in repository %q must have an \"implementation\" directory with just one %s source file to transpile", packagePath, ctx.Repository.Name(), sourceLanguage.Name()) | ||
} else if strings.HasSuffix(files[0], sourceLanguage.DefaultTestFileSuffix()) { | ||
return "", "", pkgerrors.Errorf("package %q in repository %q must have an \"implementation\" directory with only a %s source file, but found a test file %q", packagePath, ctx.Repository.Name(), sourceLanguage.Name(), sourceFilePath) | ||
} | ||
sourceFilePath = filepath.Join(packagePath, "implementation", sourceFilePath) | ||
|
||
stubFilePath, err = packageHasSourceAndTestFile(fileLogger, ctx.Repository.Name(), packagePath, ctx.Language) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
stubFilePath = filepath.Join(packagePath, stubFilePath) | ||
|
||
return sourceFilePath, stubFilePath, nil | ||
} |
Oops, something went wrong.