-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from onrcayci/dev
Version 1.0 Release
- Loading branch information
Showing
6 changed files
with
222 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# VS Code files | ||
.vscode/ | ||
|
||
# build files | ||
build/ |
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,9 @@ | ||
package main | ||
|
||
import "github.com/onrcayci/goshell/internal/goshell" | ||
|
||
// Main function of the goshell application. | ||
// Uses the function Shell from the goshell package inside the internal module. | ||
func main() { | ||
goshell.Shell() | ||
} |
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,128 @@ | ||
package command | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/onrcayci/goshell/internal/memory" | ||
"github.com/onrcayci/goshell/internal/parser" | ||
) | ||
|
||
// Interpreter takes in the tokenized input slice (argv) and the length of the slice(arc) | ||
// and uses a switch statement to determine which shell command to execute. | ||
// Supported commands: "help", "quit", "set", "print" and "run". | ||
func Interpreter(argc int, argv []string) { | ||
if argc == 0 { | ||
return | ||
} else { | ||
switch argv[0] { | ||
case "help": | ||
help() | ||
case "quit": | ||
quit() | ||
case "set": | ||
err := set(argc, argv) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
} | ||
case "print": | ||
err := print(argc, argv) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
} | ||
case "run": | ||
err := run(argc, argv) | ||
if err != nil { | ||
fmt.Println(err.Error()) | ||
} | ||
default: | ||
fmt.Printf("%s: command not found\n", argv[0]) | ||
} | ||
} | ||
} | ||
|
||
// Function help which implements the "help" shell command. | ||
// Returns the help text which outputs all of the supported commands | ||
// and their description. | ||
func help() { | ||
helpText := `Go Shell v1.0 | ||
Available Commands: | ||
COMMAND DESCRIPTION | ||
help Displays all the commands | ||
quit Exits / terminates the shell with "Bye!" | ||
set VAR STRING Assigns a value to shell memory | ||
print VAR Displays the STRING assigned to VAR | ||
run SCRIPT.TXT Executes the file SCRIPT.TXT | ||
` | ||
fmt.Println(helpText) | ||
} | ||
|
||
// Function quit which implements the "quit" shell command. | ||
// Prints out the message "Bye!" on the screen and end the appliction runtime | ||
// using the function os.Exit(0). | ||
func quit() { | ||
fmt.Println("Bye!") | ||
os.Exit(0) | ||
} | ||
|
||
// Function set which implements the "set" shell command. | ||
// Creates and saves a new shell environment variable into the runtime if the | ||
// runtime does not exist. If the variable exists, it updates the value of it | ||
// using the new value passed into the command. | ||
// Returns an error if the number of arguments is less than 3 (i.e. "set VAR VALUE"). | ||
func set(argc int, args []string) error { | ||
if argc < 3 { | ||
return errors.New("missing arguments!\nusage: set VAR VALUE") | ||
} | ||
memory.NewMemoryItem(args[1], args[2]) | ||
return nil | ||
} | ||
|
||
// Function print which implements the "print" shell command. | ||
// Displays the value of a saved shell environment variable if it exists. | ||
// Otherwise, displays the error message "variable does not exist". | ||
// Returns an error if the number of arguments is less than 2 (i.e. "print VAR") | ||
func print(argc int, args []string) error { | ||
if argc < 2 { | ||
return errors.New("missing arguments!\nusage: print VAR") | ||
} | ||
varValue := memory.FindMemoryItem(args[1]) | ||
if varValue == "" { | ||
return errors.New("variable does not exist") | ||
} | ||
fmt.Println(varValue) | ||
return nil | ||
} | ||
|
||
// Function run which implements the "run" shell command. | ||
// This function enables users to run shell scripts with supported commands. | ||
// Returns an error if the number of arguments is less than 2 (i.e. "run SCRIPT.TXT"). | ||
// BUG(onrcayci): The function parser.ParseInput parses the filename into 3 tokens, i.e., [<filename> "." <file extension>]. | ||
func run(argc int, args []string) error { | ||
if argc < 2 { | ||
return errors.New("missing arguments!\nusage: run SCRIPT.TXT") | ||
} | ||
|
||
// due to the file name tokenization bug, the filename is provided using 3 arguments from args: | ||
// args[1] = file name, args[2] = ".", args[3] = file extension. | ||
script, err := os.Open(args[1] + args[2] + args[3]) | ||
if err != nil { | ||
return err | ||
} | ||
reader := bufio.NewReader(script) | ||
for { | ||
line, err := reader.ReadString('\n') | ||
if err == io.EOF { | ||
break | ||
} else if err != nil { | ||
return err | ||
} | ||
argc, argv := parser.ParseInput(line) | ||
Interpreter(argc, argv) | ||
} | ||
return nil | ||
} |
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,26 @@ | ||
package goshell | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/onrcayci/goshell/internal/command" | ||
"github.com/onrcayci/goshell/internal/parser" | ||
) | ||
|
||
// Shell implements the main shell infinite loop. It accepts input from the user, | ||
// parses the input into tokens and then uses the interpreter function to execute | ||
// the desired command. | ||
func Shell() { | ||
reader := bufio.NewReader(os.Stdin) | ||
for { | ||
fmt.Printf(">> ") | ||
input, err := reader.ReadString('\n') | ||
if err != nil { | ||
panic(err) | ||
} | ||
argc, argv := parser.ParseInput(input) | ||
command.Interpreter(argc, argv) | ||
} | ||
} |
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,35 @@ | ||
package memory | ||
|
||
// Shell environment variable struct. | ||
// Variable = name of the variable, | ||
// Value = value the variable holds. | ||
type mem struct { | ||
variable string | ||
value string | ||
} | ||
|
||
// Shell environment variables slice. | ||
// Holds the environment variables available in the current runtime. | ||
var memory []*mem | ||
|
||
// Function to add a new environment variable to the shell memory. | ||
func NewMemoryItem(variable, value string) { | ||
for _, v := range memory { | ||
if v.variable == variable { | ||
v.value = value | ||
return | ||
} | ||
} | ||
memoryItem := &mem{variable, value} | ||
memory = append(memory, memoryItem) | ||
} | ||
|
||
// Function to find an environment variable with the given variable name. | ||
func FindMemoryItem(variable string) string { | ||
for _, v := range memory { | ||
if v.variable == variable { | ||
return v.value | ||
} | ||
} | ||
return "" | ||
} |
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,19 @@ | ||
package parser | ||
|
||
import ( | ||
"strings" | ||
"text/scanner" | ||
) | ||
|
||
// Function to parse the input into string tokens. | ||
// Retunrs the number of tokens (argc) and the tokens (args). | ||
func ParseInput(input string) (int, []string) { | ||
var args []string | ||
var scan scanner.Scanner | ||
scan.Init(strings.NewReader(input)) | ||
for token := scan.Scan(); token != scanner.EOF; token = scan.Scan() { | ||
arg := scan.TokenText() | ||
args = append(args, arg) | ||
} | ||
return len(args), args | ||
} |