second commit
This commit is contained in:
parent
b662afe779
commit
36d2b8e03a
|
@ -0,0 +1 @@
|
|||
fsh
|
|
@ -0,0 +1,13 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Sekulum Forka"
|
||||
description = "A shell inspired by tcl"
|
||||
license = "AGPL-3.0-only"
|
||||
srcDir = "src"
|
||||
bin = @["fsh"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 1.4.4"
|
|
@ -0,0 +1,165 @@
|
|||
# fsh - Forka shell
|
||||
# 2021 - Seculum Forka
|
||||
# This program is licensed under the agpl v3.0 only license
|
||||
|
||||
# imports
|
||||
import streams
|
||||
import strutils
|
||||
import osproc
|
||||
|
||||
# forward declarations
|
||||
proc eval(cmd: string): string
|
||||
|
||||
# skipSpaces reads the stream until a non-space character is found
|
||||
proc skipSpaces(strm: Stream): int =
|
||||
while not strm.atEnd():
|
||||
if strm.peekChar() == ' ':
|
||||
discard strm.readChar()
|
||||
result.inc
|
||||
else: break
|
||||
|
||||
# readLiterals parses the string passed in as a literal, preserving all braces except the first and last ones
|
||||
proc readLiteral(strm: Stream): string =
|
||||
var numbraces=1
|
||||
while not strm.atEnd() and numbraces > 0:
|
||||
let c = strm.readChar()
|
||||
case c:
|
||||
of '{':
|
||||
numbraces.inc
|
||||
of '}':
|
||||
numbraces = numbraces - 1
|
||||
of '\\':
|
||||
if strm.peekChar notin {'{', '}'}: result.add(strm.readChar)
|
||||
result.add(strm.readChar)
|
||||
else:
|
||||
result.add(c)
|
||||
|
||||
# a forward declaration. Fuck this shit
|
||||
proc readSubstitution(strm: Stream): string
|
||||
|
||||
# readInterpelation reads the interpelation in etween [ and ]
|
||||
proc readInterpelation(strm: Stream): string =
|
||||
while not strm.atEnd():
|
||||
let c = strm.readChar()
|
||||
case c:
|
||||
of '{':
|
||||
result.add('{')
|
||||
result.add(strm.readLiteral)
|
||||
result.add('}')
|
||||
of '[':
|
||||
result.add('[')
|
||||
result.add(strm.readInterpelation)
|
||||
result.add(']')
|
||||
of '"':
|
||||
result.add("\"")
|
||||
result.add(strm.readSubstitution)
|
||||
result.add("\"")
|
||||
of '\\':
|
||||
result.add("\\")
|
||||
result.add(strm.readChar())
|
||||
of ']':
|
||||
break
|
||||
else: result.add(c)
|
||||
|
||||
# readSubstitution reads a substitutionbetween "quotes"
|
||||
proc readSubstitution(strm: Stream): string =
|
||||
while not strm.atEnd():
|
||||
let c = strm.readChar()
|
||||
case c:
|
||||
of '{':
|
||||
result.add('{')
|
||||
result.add(strm.readLiteral)
|
||||
result.add('}')
|
||||
of '[':
|
||||
result.add('[')
|
||||
result.add(strm.readInterpelation)
|
||||
result.add(']')
|
||||
of '"':
|
||||
break
|
||||
of '\\':
|
||||
result.add("\\")
|
||||
result.add(strm.readChar())
|
||||
else: result.add(c)
|
||||
|
||||
# readCommand reads a command from stream
|
||||
proc readCommand(strm: Stream): string =
|
||||
while not strm.atEnd():
|
||||
let c = strm.readChar()
|
||||
case c:
|
||||
of '{':
|
||||
result.add('{')
|
||||
result.add(strm.readLiteral)
|
||||
result.add('}')
|
||||
of '[':
|
||||
result.add('[')
|
||||
result.add(strm.readInterpelation)
|
||||
result.add(']')
|
||||
of '"':
|
||||
result.add("\"")
|
||||
result.add(strm.readSubstitution)
|
||||
result.add("\"")
|
||||
of '\\':
|
||||
result.add("\\")
|
||||
result.add(strm.readChar())
|
||||
of '\n', '\r', ';': break
|
||||
else: result.add(c)
|
||||
|
||||
# substitute does a substitution on the stream passed in
|
||||
proc substitute(strm: Stream, delim=";\p"): string =
|
||||
while not strm.atEnd():
|
||||
let c = strm.readChar()
|
||||
if c in delim: break
|
||||
case c:
|
||||
of '{':
|
||||
result.add(strm.readLiteral)
|
||||
of '}':
|
||||
stderr.write("Extra closing brace")
|
||||
of '[':
|
||||
result.add(strm.readInterpelation.eval)
|
||||
of ']':
|
||||
stderr.write("Extra closing bracket")
|
||||
of '\\':
|
||||
result.add(strm.readChar())
|
||||
else:
|
||||
result.add(c)
|
||||
|
||||
# parseCommand parses the string given into a list representing a command
|
||||
proc parseCommand(cmd: string): seq[string] =
|
||||
var newitem = ""
|
||||
let strm = newStringStream(cmd)
|
||||
while true:
|
||||
if strm.atEnd():
|
||||
result.add(newitem)
|
||||
break
|
||||
let c = strm.readChar()
|
||||
case c:
|
||||
of '{':
|
||||
newitem.add(strm.readLiteral)
|
||||
of '[':
|
||||
newitem.add(strm.readInterpelation.eval)
|
||||
of '"':
|
||||
newitem.add(strm.readSubstitution.newStringStream.substitute)
|
||||
of ' ':
|
||||
result.add(newitem)
|
||||
newitem = ""
|
||||
discard strm.skipSpaces()
|
||||
else: newitem.add(c)
|
||||
|
||||
# executes executes the command. For now it involves catting the command and printing it
|
||||
proc execute(cmd: seq[string]): string =
|
||||
let progname=cmd[0]
|
||||
let args = cmd[1..cmd.high]
|
||||
let ps = startProcess(progname, args=args, options={poUsePath})
|
||||
result=ps.outputStream.readAll
|
||||
ps.close
|
||||
|
||||
|
||||
# eval evaluates the given string
|
||||
proc eval(cmd: string): string =
|
||||
let parsed = cmd.parseCommand
|
||||
result = parsed.execute
|
||||
|
||||
when isMainModule:
|
||||
let stdinstrm = stdin.newFileStream
|
||||
while not stdinstrm.atEnd():
|
||||
stdinstrm.readCommand.eval.echo
|
Loading…
Reference in New Issue