From 58eef23837f7b42cd10939bf26836f755995f5cb Mon Sep 17 00:00:00 2001
From: Aleksander Einarsen <aleksace@stud.ntnu.no>
Date: Wed, 9 Oct 2024 22:48:37 +0200
Subject: [PATCH] Refactored the previous compiler code into a less
 overengineered version, and seperated the code into different folders

---
 modules/compiler_V2/compiler2.go              | 83 -------------------
 modules/compiler_V2/compilers.go              |  1 +
 modules/compiler_V2/consts/consts.go          |  3 +
 modules/compiler_V2/data/OS.go                |  9 ++
 modules/compiler_V2/data/language.go          |  8 ++
 .../compiler_V2/go-compiler2/go_compiler.go   | 32 ++++---
 .../go-compiler2/go_compiler_test.go          |  6 +-
 .../rust-compiler2/rust_compiler.go           | 60 ++++++++++++++
 .../rust-compiler2/rust_compiler_test.go      | 51 ++++++++++++
 .../compiler_V2/rust-compiler2/should_compile |  3 +
 .../should_compile_with_dependencies          | 13 +++
 .../rust-compiler2/should_not_compile         |  3 +
 modules/compiler_V2/utils/make_command.go     | 17 ++++
 modules/compiler_V2/utils/setup.go            | 20 +++++
 14 files changed, 206 insertions(+), 103 deletions(-)
 delete mode 100644 modules/compiler_V2/compiler2.go
 create mode 100644 modules/compiler_V2/compilers.go
 create mode 100644 modules/compiler_V2/consts/consts.go
 create mode 100644 modules/compiler_V2/data/OS.go
 create mode 100644 modules/compiler_V2/data/language.go
 create mode 100644 modules/compiler_V2/rust-compiler2/rust_compiler.go
 create mode 100644 modules/compiler_V2/rust-compiler2/rust_compiler_test.go
 create mode 100644 modules/compiler_V2/rust-compiler2/should_compile
 create mode 100644 modules/compiler_V2/rust-compiler2/should_compile_with_dependencies
 create mode 100644 modules/compiler_V2/rust-compiler2/should_not_compile
 create mode 100644 modules/compiler_V2/utils/make_command.go
 create mode 100644 modules/compiler_V2/utils/setup.go

diff --git a/modules/compiler_V2/compiler2.go b/modules/compiler_V2/compiler2.go
deleted file mode 100644
index bf28ce0..0000000
--- a/modules/compiler_V2/compiler2.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package compiler_V2
-
-import (
-	"os"
-	"os/exec"
-)
-
-type LanguageData struct {
-	Name       Language
-	FileSuffix string // Like .go or .rs
-}
-
-type Language string
-
-const (
-	Go   Language = "go"
-	Rust Language = "rust"
-)
-
-type OS string
-
-const (
-	Windows OS = "windows"
-	Linux   OS = "linux"
-	MacOS   OS = "darwin"
-)
-
-type SourceCode string
-type Dependencies []string
-
-type Compiler struct {
-	OS           OS
-	Language     Language
-	Dependencies Dependencies
-}
-
-type GoCompilerCmd struct {
-	cmd string
-}
-
-type ICompiler interface {
-	CheckCompileErrors(srcCode []byte) ([]byte, error)
-}
-
-//func NewCompiler(os OS, language Language) ICompiler {
-//	switch language {
-//	case Go:
-//		return NewGoCompiler(os)
-//	case Rust:
-//		//return RustCompiler{}.New(os)
-//		panic("Rust compiler not implemented")
-//	default:
-//		return nil
-//	}
-//}
-
-func MakeCommand(OS OS, cmd string) *exec.Cmd {
-	switch OS {
-	case Windows:
-		return exec.Command("cmd", "/c", cmd)
-	case Linux, MacOS:
-		return exec.Command("bash", "-c", cmd)
-	default:
-		panic("Unsupported OS")
-	}
-}
-
-// SetupTempFolders creates the temp output directory for compiled files, panics if it fails
-func SetupTempFolders(tempOutputDir string) {
-	// 0777 are the permissions for the directory, everyone can read, write and execute
-	err := os.MkdirAll(tempOutputDir, os.ModePerm)
-	if err != nil {
-		panic("Error creating temp output directory:\n\n" + err.Error())
-	}
-}
-
-// RemoveTempFolders removes the temp output directory for compiled files, panics if it fails
-func RemoveTempFolders(tempOutputDir string) {
-	err := os.RemoveAll(tempOutputDir)
-	if err != nil {
-		panic("Error removing temp output directory:\n\n" + err.Error())
-	}
-}
diff --git a/modules/compiler_V2/compilers.go b/modules/compiler_V2/compilers.go
new file mode 100644
index 0000000..b42f93f
--- /dev/null
+++ b/modules/compiler_V2/compilers.go
@@ -0,0 +1 @@
+package compiler_V2
diff --git a/modules/compiler_V2/consts/consts.go b/modules/compiler_V2/consts/consts.go
new file mode 100644
index 0000000..6ad098a
--- /dev/null
+++ b/modules/compiler_V2/consts/consts.go
@@ -0,0 +1,3 @@
+package consts
+
+const TempOutputDir = "tempOutput/"
diff --git a/modules/compiler_V2/data/OS.go b/modules/compiler_V2/data/OS.go
new file mode 100644
index 0000000..b1f2338
--- /dev/null
+++ b/modules/compiler_V2/data/OS.go
@@ -0,0 +1,9 @@
+package data
+
+type OS string
+
+const (
+	Windows OS = "windows"
+	Linux   OS = "linux"
+	MacOS   OS = "darwin"
+)
diff --git a/modules/compiler_V2/data/language.go b/modules/compiler_V2/data/language.go
new file mode 100644
index 0000000..07fb9da
--- /dev/null
+++ b/modules/compiler_V2/data/language.go
@@ -0,0 +1,8 @@
+package data
+
+type Language string
+
+const (
+	Go   Language = "go"
+	Rust Language = "rust"
+)
diff --git a/modules/compiler_V2/go-compiler2/go_compiler.go b/modules/compiler_V2/go-compiler2/go_compiler.go
index 4494e22..ead1ae1 100644
--- a/modules/compiler_V2/go-compiler2/go_compiler.go
+++ b/modules/compiler_V2/go-compiler2/go_compiler.go
@@ -1,35 +1,33 @@
 package go_compiler2
 
 import (
-	c2 "compiler_V2"
+	"compiler_V2/consts"
+	"compiler_V2/data"
+	"compiler_V2/utils"
 	"os"
 )
 
+const fileName = "main.go"
+
 type GoCompiler struct {
-	c2.Compiler
+	OS       data.OS
+	Language data.Language
 }
 
-const TempOutputDir = "tempOutput/"
-const fileName = "main.go"
-
-func NewGoCompiler(OS c2.OS) *GoCompiler {
+func NewGoCompiler(OS data.OS) *GoCompiler {
 	return &GoCompiler{
-		Compiler: c2.Compiler{
-			OS:           OS,
-			Language:     c2.Go,
-			Dependencies: nil,
-		},
+		OS:       OS,
+		Language: data.Go,
 	}
 }
 
 func (gb *GoCompiler) CheckCompileErrors(srcCode []byte) ([]byte, error) {
 	// Make temp folders
-
-	c2.SetupTempFolders(TempOutputDir)
-	defer c2.RemoveTempFolders(TempOutputDir)
+	utils.SetupTempFolders(consts.TempOutputDir)
+	defer utils.RemoveTempFolders(consts.TempOutputDir)
 
 	// Write code to file
-	err := os.WriteFile(TempOutputDir+fileName, srcCode, 0644)
+	err := os.WriteFile(consts.TempOutputDir+fileName, srcCode, 0644)
 	if err != nil {
 		return nil, err
 	}
@@ -40,7 +38,7 @@ func (gb *GoCompiler) CheckCompileErrors(srcCode []byte) ([]byte, error) {
 	cmdString += " && go build -o main " + fileName
 
 	//cmdSlice := strings.Fields(cmdString)
-	cmd := c2.MakeCommand(gb.OS, cmdString)
-	cmd.Dir = TempOutputDir
+	cmd := utils.MakeCommand(gb.OS, cmdString)
+	cmd.Dir = consts.TempOutputDir
 	return cmd.CombinedOutput()
 }
diff --git a/modules/compiler_V2/go-compiler2/go_compiler_test.go b/modules/compiler_V2/go-compiler2/go_compiler_test.go
index 3d6c57f..ab38ecc 100644
--- a/modules/compiler_V2/go-compiler2/go_compiler_test.go
+++ b/modules/compiler_V2/go-compiler2/go_compiler_test.go
@@ -1,7 +1,7 @@
 package go_compiler2
 
 import (
-	c2 "compiler_V2"
+	"compiler_V2/data"
 	"os"
 	"testing"
 )
@@ -35,10 +35,10 @@ func TestCompileStringToGo(t *testing.T) {
 			// Read the code from the file
 			code, err := os.ReadFile(test.filename)
 
-			output, err := NewGoCompiler(c2.Windows).CheckCompileErrors(code)
+			output, err := NewGoCompiler(data.Windows).CheckCompileErrors(code)
 
 			if err != nil && test.shouldCompile {
-				t.Errorf("Expected the code to compile, but got an error: %v", err)
+				t.Errorf("Expected the code to compile, but got an output: %v \n error: %v", string(output), err)
 			} else if err == nil && !test.shouldCompile {
 				t.Errorf("Expected the code to not compile, but got no error")
 			}
diff --git a/modules/compiler_V2/rust-compiler2/rust_compiler.go b/modules/compiler_V2/rust-compiler2/rust_compiler.go
new file mode 100644
index 0000000..52f18b4
--- /dev/null
+++ b/modules/compiler_V2/rust-compiler2/rust_compiler.go
@@ -0,0 +1,60 @@
+package rust_compiler2
+
+import (
+	"compiler_V2/consts"
+	"compiler_V2/data"
+	"compiler_V2/utils"
+	"os"
+	"strings"
+)
+
+const fileName = "main.rs"
+
+type RustCompiler struct {
+	OS       data.OS
+	Language data.Language
+}
+
+func NewRustCompiler(OS data.OS) *RustCompiler {
+	return &RustCompiler{
+		OS:       OS,
+		Language: data.Rust,
+	}
+}
+
+func (gb *RustCompiler) CheckCompileErrors(srcCode []byte, dependencies ...string) ([]byte, error) {
+	// Make temp folders
+	utils.SetupTempFolders(consts.TempOutputDir)
+	defer utils.RemoveTempFolders(consts.TempOutputDir)
+
+	// Init cargo
+	if err := initCargo(gb.OS); err != nil {
+		return nil, err
+	}
+
+	// Write code to file
+	if err := os.WriteFile(consts.TempOutputDir+"src/"+fileName, srcCode, 0644); err != nil {
+		return nil, err
+	}
+
+	cmdString := ""
+	// Add dependencies
+	if dependencies != nil {
+		cmdString = "cargo add " + strings.Join(dependencies, " ") + " &&"
+	}
+
+	// Run go build
+	cmdString += " cargo check"
+
+	//cmdSlice := strings.Fields(cmdString)
+	cmd := utils.MakeCommand(gb.OS, cmdString)
+	cmd.Dir = consts.TempOutputDir
+	return cmd.CombinedOutput()
+}
+
+func initCargo(OS data.OS) error {
+	// Init cargo
+	cmd := utils.MakeCommand(OS, "cargo init --bin")
+	cmd.Dir = consts.TempOutputDir
+	return cmd.Run()
+}
diff --git a/modules/compiler_V2/rust-compiler2/rust_compiler_test.go b/modules/compiler_V2/rust-compiler2/rust_compiler_test.go
new file mode 100644
index 0000000..87533db
--- /dev/null
+++ b/modules/compiler_V2/rust-compiler2/rust_compiler_test.go
@@ -0,0 +1,51 @@
+package rust_compiler2
+
+import (
+	"compiler_V2/data"
+	"os"
+	"testing"
+)
+
+func TestCompileStringToRust(t *testing.T) {
+
+	tests := []struct {
+		filename      string
+		shouldCompile bool
+		dependencies  []string
+	}{
+		{
+			filename:      "should_compile",
+			shouldCompile: true,
+			dependencies:  nil,
+		},
+		{
+			filename:      "should_not_compile",
+			shouldCompile: false,
+			dependencies:  nil,
+		},
+		{
+			filename:      "should_compile_with_dependencies",
+			shouldCompile: true,
+			dependencies:  []string{"rand", "colored"},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.filename, func(t *testing.T) {
+			// Read the code from the file
+			code, err := os.ReadFile(test.filename)
+
+			output, err := NewRustCompiler(data.Windows).CheckCompileErrors(code, test.dependencies...)
+
+			if err != nil && test.shouldCompile {
+				t.Errorf("Expected the code to compile, but got an output: %v \n error: %v", string(output), err)
+			} else if err == nil && !test.shouldCompile {
+				t.Errorf("Expected the code to not compile, but got no error")
+			}
+			// Check if the output is empty when the code shouldn't compile
+			if output == nil && !test.shouldCompile {
+				t.Errorf("Expected compiler error output, but got none")
+			}
+		})
+	}
+}
diff --git a/modules/compiler_V2/rust-compiler2/should_compile b/modules/compiler_V2/rust-compiler2/should_compile
new file mode 100644
index 0000000..19e7b94
--- /dev/null
+++ b/modules/compiler_V2/rust-compiler2/should_compile
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, Should Compile :)");
+}
\ No newline at end of file
diff --git a/modules/compiler_V2/rust-compiler2/should_compile_with_dependencies b/modules/compiler_V2/rust-compiler2/should_compile_with_dependencies
new file mode 100644
index 0000000..5a39cda
--- /dev/null
+++ b/modules/compiler_V2/rust-compiler2/should_compile_with_dependencies
@@ -0,0 +1,13 @@
+use rand::Rng; // Import the Rng trait from the rand crate
+use colored::*; // Import colored for terminal text coloring
+
+fn main() {
+    // Create a random number generator
+    let mut rng = rand::thread_rng();
+
+    // Generate a random number between 1 and 100
+    let random_number = rng.gen_range(1..=100); // Inclusive range
+
+    // Print the random number in green
+    println!("Random number between 1 and 100: {}", random_number.to_string().green());
+}
\ No newline at end of file
diff --git a/modules/compiler_V2/rust-compiler2/should_not_compile b/modules/compiler_V2/rust-compiler2/should_not_compile
new file mode 100644
index 0000000..70a13aa
--- /dev/null
+++ b/modules/compiler_V2/rust-compiler2/should_not_compile
@@ -0,0 +1,3 @@
+fn main()
+    println!("Hello, Should Not Compile :(")
+}
\ No newline at end of file
diff --git a/modules/compiler_V2/utils/make_command.go b/modules/compiler_V2/utils/make_command.go
new file mode 100644
index 0000000..cffa76c
--- /dev/null
+++ b/modules/compiler_V2/utils/make_command.go
@@ -0,0 +1,17 @@
+package utils
+
+import (
+	"compiler_V2/data"
+	"os/exec"
+)
+
+func MakeCommand(OS data.OS, cmd string) *exec.Cmd {
+	switch OS {
+	case data.Windows:
+		return exec.Command("cmd", "/c", cmd)
+	case data.Linux, data.MacOS:
+		return exec.Command("bash", "-c", cmd)
+	default:
+		panic("Unsupported OS")
+	}
+}
diff --git a/modules/compiler_V2/utils/setup.go b/modules/compiler_V2/utils/setup.go
new file mode 100644
index 0000000..c7e44cd
--- /dev/null
+++ b/modules/compiler_V2/utils/setup.go
@@ -0,0 +1,20 @@
+package utils
+
+import "os"
+
+// SetupTempFolders creates the temp output directory for compiled files, panics if it fails
+func SetupTempFolders(tempOutputDir string) {
+	// 0777 are the permissions for the directory, everyone can read, write and execute
+	err := os.MkdirAll(tempOutputDir, os.ModePerm)
+	if err != nil {
+		panic("Error creating temp output directory:\n\n" + err.Error())
+	}
+}
+
+// RemoveTempFolders removes the temp output directory for compiled files, panics if it fails
+func RemoveTempFolders(tempOutputDir string) {
+	err := os.RemoveAll(tempOutputDir)
+	if err != nil {
+		panic("Error removing temp output directory:\n\n" + err.Error())
+	}
+}
-- 
GitLab