Reverted to old style REPL and added note in the README

This commit is contained in:
Mattia Giambirtone 2022-11-05 12:38:05 +01:00
parent 3dead5a555
commit 26e16e7f8e
3 changed files with 45 additions and 34 deletions

View File

@ -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 **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! 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** 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 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 peon is a statically-typed, functional language which aims to allow low-level interfacing with C and Nim code while

View File

@ -55,10 +55,11 @@ $ peon file.pbc Runs the given Peon bytecode file
Command-line options Command-line options
-------------------- --------------------
-h, --help Shows this help text and exits -h, --help Show this help text and exits
-v, --version Prints the peon version number and exits -v, --version Print the peon version number and exits
-s, --string Executes the passed string as if it was a file -s, --string Execute the passed string as if it was a file
-i, --interactive Enables interactive mode: a REPL session is opened after execution -n, --nodump Don't dump the result of compilation to a *.pbc file
-d, --nodump Disables dumping the result of bytecode compilation to files -b, --breakpoints Run the debugger at specific bytecode offsets (comma-separated).
-b, --breakpoints Pauses execution of the peon virtual machine and runs the debugger at specific bytecode offsets Only available when compiled with -d:debugVM
-d, --disassemble Disassemble the given bytecode file instead of executing it
""" """

View File

@ -55,21 +55,19 @@ proc repl =
compiled: Chunk = newChunk() compiled: Chunk = newChunk()
serialized: Serialized serialized: Serialized
tokenizer = newLexer() tokenizer = newLexer()
parser = newParser()
compiler = newCompiler(replMode=true)
vm = newPeonVM() vm = newPeonVM()
debugger = newDebugger() debugger = newDebugger()
serializer = newSerializer() serializer = newSerializer()
editor = getLineEditor() editor = getLineEditor()
input: string input: string
current: string current: string
incremental: bool = false
tokenizer.fillSymbolTable() tokenizer.fillSymbolTable()
editor.bindEvent(jeQuit): editor.bindEvent(jeQuit):
stdout.styledWriteLine(fgGreen, "Goodbye!") stdout.styledWriteLine(fgGreen, "Goodbye!")
editor.prompt = "=> " editor.prompt = "=> "
keep = false keep = false
input = "" input = ""
current = ""
editor.bindKey("ctrl+a"): editor.bindKey("ctrl+a"):
editor.content.home() editor.content.home()
editor.bindKey("ctrl+e"): editor.bindKey("ctrl+e"):
@ -77,18 +75,20 @@ proc repl =
while keep: while keep:
try: try:
input = editor.read() input = editor.read()
if input.len() == 0: if input == "#reset":
continue
elif input == "#reset":
compiled = newChunk() compiled = newChunk()
compiler = newCompiler() current = ""
parser = newParser()
incremental = false
continue continue
elif input == "#show":
echo current
elif input == "#clear": elif input == "#clear":
stdout.write("\x1Bc") stdout.write("\x1Bc")
continue continue
tokens = tokenizer.lex(input, "stdin") else:
current &= input & "\n"
if current.len() == 0:
continue
tokens = tokenizer.lex(current, "stdin")
if tokens.len() == 0: if tokens.len() == 0:
continue continue
when debugLexer: when debugLexer:
@ -99,7 +99,7 @@ proc repl =
break break
styledEcho fgGreen, "\t", $token styledEcho fgGreen, "\t", $token
echo "" echo ""
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input, persist=true) tree = newParser().parse(tokens, "stdin", tokenizer.getLines(), current)
if tree.len() == 0: if tree.len() == 0:
continue continue
when debugParser: when debugParser:
@ -107,8 +107,7 @@ proc repl =
for node in tree: for node in tree:
styledEcho fgGreen, "\t", $node styledEcho fgGreen, "\t", $node
echo "" echo ""
discard compiler.compile(tree, "stdin", tokenizer.getLines(), input, chunk=compiled, incremental=incremental) compiled = newCompiler(replMode=true).compile(tree, "stdin", tokenizer.getLines(), current)
incremental = true
when debugCompiler: when debugCompiler:
styledEcho fgCyan, "Compilation step:\n" styledEcho fgCyan, "Compilation step:\n"
debugger.disassembleChunk(compiled, "stdin") debugger.disassembleChunk(compiled, "stdin")
@ -141,7 +140,6 @@ proc repl =
styledEcho fgRed, "Corrupted" styledEcho fgRed, "Corrupted"
vm.run(serialized.chunk) vm.run(serialized.chunk)
except LexingError: except LexingError:
input = ""
var exc = LexingError(getCurrentException()) var exc = LexingError(getCurrentException())
let relPos = exc.lexer.getRelPos(exc.line) let relPos = exc.lexer.getRelPos(exc.line)
let line = exc.lexer.getSource().splitLines()[exc.line - 1].strip(chars={'\n'}) 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 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))) styledEcho fgCyan, " ".repeat(len("Source line: ") + line.find(exc.lexeme)) & "^".repeat(abs(relPos.stop - relPos.start - line.find(exc.lexeme)))
except ParseError: except ParseError:
input = ""
let exc = ParseError(getCurrentException()) let exc = ParseError(getCurrentException())
let lexeme = exc.token.lexeme let lexeme = exc.token.lexeme
var lineNo = exc.token.line var lineNo = exc.token.line
if exc.token.kind == EndOfFile:
dec(lineNo)
let relPos = exc.parser.getRelPos(lineNo) let relPos = exc.parser.getRelPos(lineNo)
let fn = parser.getCurrentFunction() let fn = exc.parser.getCurrentFunction()
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) let line = exc.parser.getSource().splitLines()[lineNo - 1].strip()
var fnMsg = "" var fnMsg = ""
if fn != nil and fn.kind == funDecl: if fn != nil and fn.kind == funDecl:
fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'" fnMsg &= &"in function '{FunDecl(fn).name.token.lexeme}'"
@ -187,7 +186,7 @@ proc repl =
quit(0) 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 var
tokens: seq[Token] = @[] tokens: seq[Token] = @[]
tree: seq[Declaration] = @[] tree: seq[Declaration] = @[]
@ -204,8 +203,11 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
try: try:
var f = f var f = f
if not fromString: if not fromString:
if not f.endsWith(".pn"): if not f.endsWith(".pn") and not f.endsWith(".pbc"):
f &= ".pn" f &= ".pn"
if dis:
debugger.disassembleChunk(serializer.loadFile(f).chunk, f)
return
input = readFile(f) input = readFile(f)
else: else:
input = f input = f
@ -238,7 +240,7 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
if path.len() > 0: if path.len() > 0:
path &= "/" path &= "/"
path &= splitFile(f).name & ".pbc" path &= splitFile(f).name & ".pbc"
if dump or not fromString: if dump and not fromString:
serializer.dumpFile(compiled, f, path) serializer.dumpFile(compiled, f, path)
serialized = serializer.loadFile(path) serialized = serializer.loadFile(path)
else: else:
@ -281,6 +283,8 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false, dum
let exc = ParseError(getCurrentException()) let exc = ParseError(getCurrentException())
let lexeme = exc.token.lexeme let lexeme = exc.token.lexeme
var lineNo = exc.token.line var lineNo = exc.token.line
if exc.token.kind == EndOfFile:
dec(lineNo)
let relPos = exc.parser.getRelPos(lineNo) let relPos = exc.parser.getRelPos(lineNo)
let fn = parser.getCurrentFunction() let fn = parser.getCurrentFunction()
let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'}) let line = exc.parser.getSource().splitLines()[lineNo - 1].strip(chars={'\n'})
@ -322,9 +326,9 @@ when isMainModule:
var optParser = initOptParser(commandLineParams()) var optParser = initOptParser(commandLineParams())
var file: string = "" var file: string = ""
var fromString: bool = false var fromString: bool = false
var interactive: bool = false
var dump: bool = true var dump: bool = true
var breaks: seq[uint64] = @[] var breaks: seq[uint64] = @[]
var dis: bool = false
for kind, key, value in optParser.getopt(): for kind, key, value in optParser.getopt():
case kind: case kind:
of cmdArgument: of cmdArgument:
@ -340,8 +344,6 @@ when isMainModule:
of "string": of "string":
file = key file = key
fromString = true fromString = true
of "interactive":
interactive = true
of "no-dump": of "no-dump":
dump = false dump = false
of "breakpoints": of "breakpoints":
@ -354,6 +356,8 @@ when isMainModule:
except ValueError: except ValueError:
echo &"error: invalid breakpoint value '{point}'" echo &"error: invalid breakpoint value '{point}'"
quit() quit()
of "disassemble":
dis = true
else: else:
echo &"error: unkown option '{key}'" echo &"error: unkown option '{key}'"
quit() quit()
@ -368,9 +372,7 @@ when isMainModule:
of "s": of "s":
file = key file = key
fromString = true fromString = true
of "i": of "n":
interactive = true
of "d":
dump = false dump = false
of "b": of "b":
when not debugVM: when not debugVM:
@ -382,17 +384,18 @@ when isMainModule:
except ValueError: except ValueError:
echo &"error: invalid breakpoint value '{point}'" echo &"error: invalid breakpoint value '{point}'"
quit() quit()
of "d":
dis = true
else: else:
echo &"error: unkown option '{key}'" echo &"error: unkown option '{key}'"
quit() quit()
else: else:
echo "usage: peon [options] [filename.pn]" echo "usage: peon [options] [filename.pn]"
quit() quit()
# TODO: Use interactive
if file == "": if file == "":
repl() repl()
else: else:
runFile(file, interactive, fromString, dump, breaks) runFile(file, fromString, dump, breaks, dis)