From dbcc68fdfb165b269f98dc9a8b529184ba6bdebe Mon Sep 17 00:00:00 2001
From: Boming Zhang <bomingzh@sjtu.edu.cn>
Date: Wed, 3 Apr 2024 18:09:06 -0400
Subject: [PATCH] feat: cpplint parser

---
 internal/parsers/all.go            |  1 +
 internal/parsers/cpplint/meta.go   |  9 +++++
 internal/parsers/cpplint/parser.go | 53 ++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 internal/parsers/cpplint/meta.go
 create mode 100644 internal/parsers/cpplint/parser.go

diff --git a/internal/parsers/all.go b/internal/parsers/all.go
index ecc658c..d305bd6 100644
--- a/internal/parsers/all.go
+++ b/internal/parsers/all.go
@@ -1,6 +1,7 @@
 package parsers
 
 import (
+	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/cpplint"
 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/diff"
 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy"
 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/resultstatus"
diff --git a/internal/parsers/cpplint/meta.go b/internal/parsers/cpplint/meta.go
new file mode 100644
index 0000000..33b5188
--- /dev/null
+++ b/internal/parsers/cpplint/meta.go
@@ -0,0 +1,9 @@
+package cpplint
+
+import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
+
+var name = "cpplint"
+
+func init() {
+	stage.RegisterParser(name, &Cpplint{})
+}
diff --git a/internal/parsers/cpplint/parser.go b/internal/parsers/cpplint/parser.go
new file mode 100644
index 0000000..55a7f60
--- /dev/null
+++ b/internal/parsers/cpplint/parser.go
@@ -0,0 +1,53 @@
+package cpplint
+
+import (
+	"fmt"
+	"regexp"
+	"strconv"
+
+	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
+)
+
+type Conf struct {
+	Score int
+}
+
+type Cpplint struct{}
+
+func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
+	stderr := executorResult.Files["stderr"]
+	pattern := `(.+):(\d+):  (.+)  \[(.+)\] \[(\d)]\n`
+	re := regexp.MustCompile(pattern)
+	matches := re.FindAllStringSubmatch(stderr, -1)
+	score := 0
+	comment := ""
+	for _, match := range matches {
+		fileName := match[1]
+		lineNum, _ := strconv.Atoi(match[2])
+		message := match[3]
+		category := match[4]
+		confidence, _ := strconv.Atoi(match[5])
+		score -= confidence
+		// TODO: add more detailed comment, just re-assemble for now
+		comment += fmt.Sprintf("%s:%d:  %s  [%s] [%d]\n",
+			fileName, lineNum, message, category, confidence)
+	}
+	return stage.ParserResult{
+		Score:   score,
+		Comment: comment,
+	}
+}
+
+func (*Cpplint) Run(results []stage.ExecutorResult, confAny any) (
+	[]stage.ParserResult, bool, error,
+) {
+	conf, err := stage.DecodeConf[Conf](confAny)
+	if err != nil {
+		return nil, true, err
+	}
+	var res []stage.ParserResult
+	for _, result := range results {
+		res = append(res, Parse(result, *conf))
+	}
+	return res, false, nil
+}