package elf import ( "encoding/json" "fmt" "log/slog" "strings" "github.com/joint-online-judge/JOJ3/internal/stage" "github.com/mitchellh/mapstructure" ) func (p *Elf) parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult { stdout := executorResult.Files[conf.Stdout] // stderr := executorResult.Files[conf.Stderr] var topLevel Toplevel err := json.Unmarshal([]byte(stdout), &topLevel) if err != nil { return stage.ParserResult{ Score: 0, Comment: fmt.Sprintf( "Unexpected parser error: %s.", err, ), } } score := conf.Score comment := "" for _, module := range topLevel.Modules { for _, entry := range module.Entries { kind := entry[0].(string) report := Report{} err := mapstructure.Decode(entry[1], &report) if err != nil { slog.Error("elf parse", "mapstructure decode err", err) } comment += fmt.Sprintf("### [%s] %s\n", report.File, report.Name) for _, caseObj := range report.Cases { for _, match := range conf.Matches { for _, keyword := range match.Keywords { if strings.Contains(kind, keyword) { score += -match.Score } } } switch kind { case "ParenDep": // ":\n below reaches a parentheses depths of :\n" comment += fmt.Sprintf( "%s:\n%s below reaches a parentheses depths of %d:\n"+ "```%s\n```\n", caseObj.Binders, caseObj.Context, caseObj.Depths, caseObj.Code, ) case "CodeLen": // ":\n below excceeds a code length upper bound with (weighed: ):\n" comment += fmt.Sprintf( "%s:\n%s below excceeds a code length "+ "upper bound with %d (weighed: %f):\n"+ "```%s\n```\n", caseObj.Binders, caseObj.Context, caseObj.Plain, caseObj.Weighed, caseObj.Code, ) case "OverArity": // ":\n below hits :\n" comment += fmt.Sprintf( "%s:\n%s below hits %s:\n```%s\n```\n", caseObj.Binders, caseObj.Context, caseObj.Detail, caseObj.Code, ) case "CodeDup": if len(caseObj.Sources) != 2 { slog.Error("elf parse", "code dup sources length", len(caseObj.Sources)) } context0 := caseObj.Sources[0].Context code0 := caseObj.Sources[0].Code context1 := caseObj.Sources[1].Context code1 := caseObj.Sources[1].Code // "The code below has a similarity rate of :\n- :\n\t\n- :\n\t" comment += fmt.Sprintf( "The code below has a similarity rate of %f:\n"+ "- %s:\n```%s\n```\n"+ "- %s:\n```%s\n```\n", caseObj.SimilarityRate, context0, code0, context1, code1, ) } } } } return stage.ParserResult{ Score: score, Comment: comment, } } func (p *Elf) Run(results []stage.ExecutorResult, confAny any) ( []stage.ParserResult, bool, error, ) { conf, err := stage.DecodeConf[Conf](confAny) if err != nil { return nil, true, err } res := make([]stage.ParserResult, 0, len(results)) forceQuit := false for _, result := range results { parseRes := p.parse(result, *conf) if conf.ForceQuitOnDeduct && parseRes.Score < conf.Score { forceQuit = true } res = append(res, parseRes) } return res, forceQuit, nil }