Compare commits

...

5 Commits

1 changed files with 38 additions and 13 deletions

View File

@ -10,7 +10,8 @@ import os
import strutils
# globals
var shellVariables = newStringTable(modeCaseSensitive)
# shellVariables are an array of vars
var shellVariables = @[newStringTable(modeCaseSensitive)]
# Environment variables get defined in a separate var
var envVariables = newStringTable(modeCaseSensitive)
# populate the table
@ -18,15 +19,19 @@ for k, v in envPairs():
envVariables[k]=v
# list of builtin commands
let builtins: array[6, string] = [
let builtins: array[7, string] = [
"set",
"setenv",
"echo",
"exit",
"if",
"cd",
"let",
]
# number of frames to be used for builtins like set
var numframes: int=1
# Exception types
type
ShellError= object of CatchableError
@ -88,8 +93,10 @@ proc readLiteral(strm: Stream): string =
case c:
of '{':
numbraces.inc
result.add('{')
of '}':
numbraces = numbraces - 1
if numbraces != 0: result.add('}')
of '\\':
if strm.peekChar notin {'{', '}'}: result.add(strm.readChar)
result.add(strm.readChar)
@ -191,9 +198,10 @@ proc readVariable(strm: Stream): string =
# evalVariable finds a value of a variable
proc evalVariable(vari: string): string =
if vari == "$": return "$"
if shellVariables.hasKey(vari):
result=shellVariables[vari]
elif envVariables.hasKey(vari):
for i in countdown((numframes-1), 0):
let frame = shellVariables[i]
if frame.hasKey(vari): return frame[vari]
if envVariables.hasKey(vari):
result = envVariables[vari]
else:
raise newShellVariableException("No such variable", vari)
@ -252,7 +260,7 @@ proc runBuiltin(builtin: string, args: openArray[string]): (string, int) =
of "set":
if args.len < 2:
raise newShellCommandException("Not enough arguments provided", "set")
shellVariables[args[0]] = args[1..^1].join(" ")
shellVariables[numframes-1][args[0]] = args[1..^1].join(" ")
return ("", 0)
of "setenv":
if args.len < 2:
@ -310,20 +318,37 @@ proc runBuiltin(builtin: string, args: openArray[string]): (string, int) =
of "cd":
try:
if args.len == 0:
shellVariables["LASTPWD"] = getCurrentDir()
shellVariables[0]["LASTPWD"] = getCurrentDir()
setCurrentDir(getHomeDir())
return ("", 0)
else:
if args[0] == "-":
let LASTPWD = getCurrentDir()
setCurrentDir(shellVariables["LASTPWD"])
shellVariables["LASTPWD"] = LASTPWD
setCurrentDir(shellVariables[0]["LASTPWD"])
shellVariables[0]["LASTPWD"] = LASTPWD
return ("", 0)
shellVariables["LASTPWD"] = getCurrentDir()
shellVariables[0]["LASTPWD"] = getCurrentDir()
setCurrentDir(args[0])
return ("", 0)
except OsError as e:
raise newShellCommandException("No such directory", "cd")
of "let":
if args.len < 2:
raise newShellCommandException("Not enough arguments provided", "let")
shellVariables.add(newStringTable(modeCaseSensitive))
numframes.inc
let varvals = args[0].parseCommand
for varval in varvals:
let varval_parsed = varval.parseCommand
if varval_parsed.len < 2:
raise newShellCommandException("Missingvalue to go with key", "let")
let vari = varval_parsed[0]
let val = varval_parsed[1]
shellVariables[numframes-1][vari]=val
result[0] = args[1].eval
discard shellVariables.pop
numframes.dec
result[1] = 0
else:
raise newShellCommandException("No such builtin implemented", builtin)
@ -374,12 +399,12 @@ when isMainModule:
setControlCHook(ctrlc)
let stdinstrm = stdin.newFileStream
# Set the default prompt
shellVariables["PROMPT"] = "$PWD \\$"
stdout.write(shellVariables["PROMPT"].newStringStream.substitute)
shellVariables[0]["PROMPT"] = "$PWD \\$"
stdout.write(shellVariables[0]["PROMPT"].newStringStream.substitute)
while not stdinstrm.atEnd():
try:
discard stdinstrm.readCommand.execute
stdout.write(shellVariables["PROMPT"].newStringStream.substitute)
stdout.write(shellVariables[0]["PROMPT"].newStringStream.substitute)
except ShellError, ShellCommandError, ShellVariableError:
let e = getCurrentException()
stderr.write(e.msg, "\n")