Reverted to old style REPL and added note in the README
This commit is contained in:
parent
3dead5a555
commit
26e16e7f8e
|
@ -42,6 +42,13 @@ Peon is a simple, functional, async-first programming language with a focus on c
|
|||
**Disclaimer**: The project is still in its very early days: lots of stuff is not implemented, a work in progress or
|
||||
otherwise outright broken. Feel free to report bugs!
|
||||
|
||||
|
||||
**Disclaimer 2**: Currently the REPL is very basic (it incrementally joins your lines with a newline, as if it was compiling a new file every time),
|
||||
because incremental compilation is designed for modules and it doesn't play well with the interactive nature of a REPL session. To show the current state
|
||||
of the REPL, type `#show` (this will print all the code that has been typed so far), while to reset everything (will un-import modules and stuff), type
|
||||
`#reset`. You can also type `#clear` if you want a clean slate to type in, but note that it won't reset the REPL state.
|
||||
|
||||
|
||||
Also, yes: peon is yet another programming language inspired by Bob's book, but it is also **very**
|
||||
different from Lox, which is an object-oriented, dynamically typed and very high level programming language, whereas
|
||||
peon is a statically-typed, functional language which aims to allow low-level interfacing with C and Nim code while
|
||||
|
|
|
@ -55,10 +55,11 @@ $ peon file.pbc Runs the given Peon bytecode file
|
|||
Command-line options
|
||||
--------------------
|
||||
|
||||
-h, --help Shows this help text and exits
|
||||
-v, --version Prints the peon version number and exits
|
||||
-s, --string Executes the passed string as if it was a file
|
||||
-i, --interactive Enables interactive mode: a REPL session is opened after execution
|
||||
-d, --nodump Disables dumping the result of bytecode compilation to files
|
||||
-b, --breakpoints Pauses execution of the peon virtual machine and runs the debugger at specific bytecode offsets
|
||||
-h, --help Show this help text and exits
|
||||
-v, --version Print the peon version number and exits
|
||||
-s, --string Execute the passed string as if it was a file
|
||||
-n, --nodump Don't dump the result of compilation to a *.pbc file
|
||||
-b, --breakpoints Run the debugger at specific bytecode offsets (comma-separated).
|
||||
Only available when compiled with -d:debugVM
|
||||
-d, --disassemble Disassemble the given bytecode file instead of executing it
|
||||
"""
|
||||
|
|
59
src/main.nim
59
src/main.nim
|
@ -55,21 +55,19 @@ proc repl =
|
|||
compiled: Chunk = newChunk()
|
||||
serialized: Serialized
|
||||
tokenizer = newLexer()
|
||||
parser = newParser()
|
||||
compiler = newCompiler(replMode=true)
|
||||
vm = newPeonVM()
|
||||
debugger = newDebugger()
|
||||
serializer = newSerializer()
|
||||
editor = getLineEditor()
|
||||
input: string
|
||||
current: string
|
||||
incremental: bool = false
|
||||
tokenizer.fillSymbolTable()
|
||||
editor.bindEvent(jeQuit):
|
||||
stdout.styledWriteLine(fgGreen, "Goodbye!")
|
||||
editor.prompt = "=> "
|
||||
keep = false
|
||||
input = ""
|
||||
current = ""
|
||||
editor.bindKey("ctrl+a"):
|
||||
editor.content.home()
|
||||
editor.bindKey("ctrl+e"):
|
||||
|
@ -77,18 +75,20 @@ proc repl =
|
|||
while keep:
|
||||
try:
|
||||
input = editor.read()
|
||||
if input.len() == 0:
|
||||
continue
|
||||
elif input == "#reset":
|
||||
if input == "#reset":
|
||||
compiled = newChunk()
|
||||
compiler = newCompiler()
|
||||
parser = newParser()
|
||||
incremental = false
|
||||
current = ""
|
||||
continue
|
||||
elif input == "#show":
|
||||
echo current
|
||||
elif input == "#clear":
|
||||
stdout.write("\x1Bc")
|
||||
continue
|
||||
tokens = tokenizer.lex(input, "stdin")
|
||||
else:
|
||||
current &= input & "\n"
|
||||
if current.len() == 0:
|
||||
continue
|
||||
tokens = tokenizer.lex(current, "stdin")
|
||||
if tokens.len() == 0:
|
||||
continue
|
||||
when debugLexer:
|
||||
|
@ -99,7 +99,7 @@ proc repl =
|
|||
break
|
||||
styledEcho fgGreen, "\t", $token
|
||||
echo ""
|
||||
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input, persist=true)
|
||||
tree = newParser().parse(tokens, "stdin", tokenizer.getLines(), current)
|
||||
if tree.len() == 0:
|
||||
continue
|
||||
when debugParser:
|
||||
|
@ -107,8 +107,7 @@ proc repl =
|
|||
for node in tree:
|
||||
styledEcho fgGreen, "\t", $node
|
||||
echo ""
|
||||
discard compiler.compile(tree, "stdin", tokenizer.getLines(), input, chunk=compiled, incremental=incremental)
|
||||
incremental = true
|
||||
compiled = newCompiler(replMode=true).compile(tree, "stdin", tokenizer.getLines(), current)
|
||||
when debugCompiler:
|
||||
styledEcho fgCyan, "Compilation step:\n"
|
||||
debugger.disassembleChunk(compiled, "stdin")
|
||||
|
@ -141,7 +140,6 @@ proc repl =
|
|||
styledEcho fgRed, "Corrupted"
|
||||
vm.run(serialized.chunk)
|
||||
except LexingError:
|
||||
input = ""
|
||||
var exc = LexingError(getCurrentException())
|
||||
let relPos = exc.lexer.getRelPos(exc.line)
|
||||
let line = exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'})
|
||||
|
@ -151,13 +149,14 @@ proc repl =
|
|||
styledEcho fgBlue, "Source line: " , fgDefault, line
|
||||
styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(exc.lexeme)))
|
||||
except ParseError:
|
||||
input = ""
|
||||
let exc = ParseError(getCurrentException())
|
||||
let lexeme = exc.token.lexeme
|
||||
var lineNo = exc.token.line
|
||||
if exc.token.kind == EndOfFile:
|
||||
dec(lineNo)
|
||||
let relPos = exc.parser.getRelPos(lineNo)
|
||||
let fn = parser.getCurrentFunction()
|
||||
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||
let fn = exc.parser.getCurrentFunction()
|
||||
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip()
|
||||
var fnMsg = ""
|
||||
if fn != nil and fn.kind == funDecl:
|
||||
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
|
||||
|
@ -187,7 +186,7 @@ proc repl =
|
|||
quit(0)
|
||||
|
||||
|
||||
proc runFile(f: string, interactive: bool = false, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[]) =
|
||||
proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[], dis: bool = false) =
|
||||
var
|
||||
tokens: seq[Token] = @[]
|
||||
tree: seq[Declaration] = @[]
|
||||
|
@ -204,8 +203,11 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
try:
|
||||
var f = f
|
||||
if not fromString:
|
||||
if not f.endsWith(".pn"):
|
||||
if not f.endsWith(".pn") and not f.endsWith(".pbc"):
|
||||
f &= ".pn"
|
||||
if dis:
|
||||
debugger.disassembleChunk(serializer.loadFile(f).chunk, f)
|
||||
return
|
||||
input = readFile(f)
|
||||
else:
|
||||
input = f
|
||||
|
@ -238,7 +240,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
if path.len() > 0:
|
||||
path &= "/"
|
||||
path &= splitFile(f).name & ".pbc"
|
||||
if dump or not fromString:
|
||||
if dump and not fromString:
|
||||
serializer.dumpFile(compiled, f, path)
|
||||
serialized = serializer.loadFile(path)
|
||||
else:
|
||||
|
@ -281,6 +283,8 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
|
|||
let exc = ParseError(getCurrentException())
|
||||
let lexeme = exc.token.lexeme
|
||||
var lineNo = exc.token.line
|
||||
if exc.token.kind == EndOfFile:
|
||||
dec(lineNo)
|
||||
let relPos = exc.parser.getRelPos(lineNo)
|
||||
let fn = parser.getCurrentFunction()
|
||||
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
|
||||
|
@ -322,9 +326,9 @@ when isMainModule:
|
|||
var optParser = initOptParser(commandLineParams())
|
||||
var file: string = ""
|
||||
var fromString: bool = false
|
||||
var interactive: bool = false
|
||||
var dump: bool = true
|
||||
var breaks: seq[uint64] = @[]
|
||||
var dis: bool = false
|
||||
for kind, key, value in optParser.getopt():
|
||||
case kind:
|
||||
of cmdArgument:
|
||||
|
@ -340,8 +344,6 @@ when isMainModule:
|
|||
of "string":
|
||||
file = key
|
||||
fromString = true
|
||||
of "interactive":
|
||||
interactive = true
|
||||
of "no-dump":
|
||||
dump = false
|
||||
of "breakpoints":
|
||||
|
@ -354,6 +356,8 @@ when isMainModule:
|
|||
except ValueError:
|
||||
echo &"error: invalid breakpoint value '{point}'"
|
||||
quit()
|
||||
of "disassemble":
|
||||
dis = true
|
||||
else:
|
||||
echo &"error: unkown option '{key}'"
|
||||
quit()
|
||||
|
@ -368,9 +372,7 @@ when isMainModule:
|
|||
of "s":
|
||||
file = key
|
||||
fromString = true
|
||||
of "i":
|
||||
interactive = true
|
||||
of "d":
|
||||
of "n":
|
||||
dump = false
|
||||
of "b":
|
||||
when not debugVM:
|
||||
|
@ -382,17 +384,18 @@ when isMainModule:
|
|||
except ValueError:
|
||||
echo &"error: invalid breakpoint value '{point}'"
|
||||
quit()
|
||||
of "d":
|
||||
dis = true
|
||||
else:
|
||||
echo &"error: unkown option '{key}'"
|
||||
quit()
|
||||
else:
|
||||
echo "usage: peon [options] [filename.pn]"
|
||||
quit()
|
||||
# TODO: Use interactive
|
||||
if file == "":
|
||||
repl()
|
||||
else:
|
||||
runFile(file, interactive, fromString, dump, breaks)
|
||||
runFile(file, fromString, dump, breaks, dis)
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue