Get rid of REPL + minor refactorings

This commit is contained in:
Mattia Giambirtone 2023-06-29 13:57:50 +02:00
parent 45c5be7470
commit 919cc25579
Signed by: nocturn9x
GPG Key ID: 8270F9F467971E59
5 changed files with 59 additions and 191 deletions

View File

@ -114,21 +114,13 @@ out for yourself. Fortunately, the process is quite straightforward:
- First, you're gonna have to install [Nim](https://nim-lang.org/), the language peon is written in. I highly recommend
using [choosenim](https://github.com/dom96/choosenim) to manage your Nim installations as it makes switching between them and updating them a breeze
- Once Nim is installed, you should install [jale](https://git.nocturn9x.space/japl/jale), peon's custom line editor
library written by our beloved [Art](https://git.nocturn9x.space/art). This is needed for the REPL to work: just clone the repository, `cd` into it and run `nimble install`; this will install the library on your
system so that the Nim compiler can find it later
- After jale has been installed, clone this repository and run the REPL with `nim r src/main` (in the appropriate
directory of course). If you want to do more than play around in the REPL, I recommend compiling peon in release
mode with `nim -d:release --passC:"-flto" -o:peon`, which should produce a `peon` binary ready for you to play with
(if your C toolchain doesn't support LTO then you can just omit the `--passC` option, although that would be pretty weird
for a modern linker)
- Then, clone this repository and compile peon in release mode with `nim c -d:release --passC:"-flto" -o:peon src/main`, which should produce`peon` binary
ready for you to play with (if your C toolchain doesn't support LTO then you can just omit the `--passC` option, although that would be pretty weird for
a modern linker)
- If you want to move the executable to a different directory (say, into your `PATH`), you should copy peon's standard
library (found in `/src/peon/stdlib`) into a known folder and edit the `moduleLookupPaths` variable inside `src/config.nim`
by adding said folder to it so that the peon compiler knows where to find modules when you `import std;`. Hopefully I will
automate this soon, but as of right now the work is all manual (and it's part of the fun, IMHO ;))
library (found in `/src/peon/stdlib`) into a known folder, edit the `moduleLookupPaths` variable inside `src/config.nim`
by adding said folder to it so that the peon compiler knows where to find modules when you `import std;` and then recompile
peon. Hopefully I will automate this soon, but as of right now the work is all manual
__Note__: On Linux, peon will also look into `~/.local/peon/stdlib`
If you've done everything right, you should be able to run `peon` in your terminal and have it drop you into the REPL. Good
luck and have fun!
__Note__: On Linux, peon will also look into `~/.local/peon/stdlib` by default, so you can just create the `~/.local/peon` folder and copy `src/peon/stdlib` there

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
## The Peon runtime environment
import ../config
import config
# Sorry, but there only is enough space
# for one GC in this VM :(
@ -30,16 +30,16 @@ import std/strutils
import std/sets
import std/monotimes
import ../frontend/compiler/targets/bytecode/opcodes
import ../frontend/compiler/targets/bytecode/util/multibyte
when debugVM or debugMem or debugGC or debugAlloc:
import std/strformat
import std/sequtils
import std/terminal
import frontend/compiler/targets/bytecode/opcodes
import frontend/compiler/targets/bytecode/util/multibyte
when debugVM:
proc clearerr(stream: File) {.header: "stdio.h", importc.}

View File

@ -48,7 +48,6 @@ http://www.apache.org/licenses/LICENSE-2.0 for more info.
Basic Usage
-----------
$ peon Open an interactive session (REPL)
$ peon file.pn Run the given Peon source file
$ peon file.pbc Run the given Peon bytecode file
@ -62,9 +61,9 @@ Options
-n, --noDump Don't dump the result of compilation to a file.
Note that no dump is created when using -s/--string
-b, --breakpoints Run the debugger at specific bytecode offsets (comma-separated).
Only available with --backend:bytecode and when compiled with VM
debugging on
-d, --disassemble Disassemble the output of compilation (only makes sense with --backend:bytecode)
Only available with --target:bytecode and when compiled with VM
debugging on (-d:debugVM at build time)
-d, --disassemble Disassemble the output of compilation (only makes sense with --target:bytecode)
-m, --mode Set the compilation mode. Acceptable values are 'debug' and
'release'. Defaults to 'debug'
-c, --compile Compile the code, but do not execute it. Useful along with -d
@ -72,11 +71,11 @@ Options
yes/on and no/off
--noWarn Disable a specific warning (for example, --noWarn:unusedVariable)
--showMismatches Show all mismatches when function dispatching fails (output is really verbose)
--backend Select the compilation backend (valid values are: 'c' and 'bytecode'). Note
that the REPL always uses the bytecode target. Defaults to 'bytecode'
-o, --output Rename the output file with this value (with --backend:bytecode, a '.pbc' extension
--target Select the compilation target (valid values are: 'c' and 'bytecode'). Defaults to
'bytecode'
-o, --output Rename the output file with this value (with --target:bytecode, a '.pbc' extension
is added if not already present)
--debug-dump Debug the bytecode serializer. Only makes sense with --backend:bytecode
--debug-lexer Debug the peon lexer
--debug-parser Debug the peon parser
--debug-dump Debug the bytecode serializer. Only makes sense with --target:bytecode
--debug-lexer Show the lexer's output
--debug-parser Show the parser's output
"""

View File

@ -829,7 +829,6 @@ proc match*(self: Compiler, name: string, kind: Type, node: ASTNode = nil, allow
msg = &"call to undefined function '{name}'"
self.error(msg, node)
elif impl.len() > 1:
echo "AAAAAA\n\n"
# If we happen to find more than one match, we try again
# and ignore forward declarations and automatic functions
impl = filterIt(impl, not it.valueType.forwarded and not it.valueType.isAuto)

View File

@ -15,149 +15,30 @@
## Peon's main executable
# Our stuff
import frontend/parsing/lexer as l
import frontend/parsing/parser as p
import frontend/compiler/targets/bytecode/target as b
import frontend/compiler/compiler as c
import backend/vm as v
import frontend/compiler/targets/bytecode/util/serializer as s
import frontend/compiler/targets/bytecode/util/debugger
import util/symbols
import util/fmterr
import config
import util/fmterr
import util/symbols
import backend/bytecode/vm
import frontend/parsing/lexer
import frontend/parsing/parser
import frontend/compiler/compiler
import frontend/compiler/targets/bytecode/util/debugger
import frontend/compiler/targets/bytecode/util/serializer
import frontend/compiler/targets/bytecode/target as bytecode
# Builtins & external libs
import std/strformat
import std/os
import std/times
import std/strutils
import std/terminal
import std/parseopt
import std/times
import std/os
# Thanks art <3
import jale/editor as ed
import jale/templates
import jale/plugin/defaults
import jale/plugin/editor_history
import jale/keycodes
import jale/multiline
proc getLineEditor: LineEditor =
result = newLineEditor()
result.prompt = "=> "
result.populateDefaults()
let history = result.plugHistory()
result.bindHistory(history)
#[
proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug, breakpoints: seq[uint64] = @[]) =
styledEcho fgMagenta, "Welcome into the peon REPL!"
var
keep = true
tokens: seq[Token] = @[]
tree: seq[Declaration] = @[]
compiler = newBytecodeCompiler(replMode=true)
compiled: Chunk = newChunk()
serialized: Serialized
tokenizer = newLexer()
vm = newPeonVM()
parser = newParser()
debugger = newDebugger()
serializer = newSerializer()
editor = getLineEditor()
input: string
first: bool = false
tokenizer.fillSymbolTable()
editor.bindEvent(jeQuit):
stdout.styledWriteLine(fgGreen, "Goodbye!")
keep = false
input = ""
editor.bindKey("ctrl+a"):
editor.content.home()
editor.bindKey("ctrl+e"):
editor.content.`end`()
while keep:
try:
input = editor.read()
if input == "#clear":
stdout.write("\x1Bc")
continue
elif input == "":
continue
tokens = tokenizer.lex(input, "stdin")
if tokens.len() == 0:
continue
if debugLexer:
styledEcho fgCyan, "Tokenization step:"
for i, token in tokens:
if i == tokens.high():
# Who cares about EOF?
break
styledEcho fgGreen, "\t", $token
echo ""
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input, persist=true)
if tree.len() == 0:
continue
if debugParser:
styledEcho fgCyan, "Parsing step:"
for node in tree:
styledEcho fgGreen, "\t", $node
echo ""
discard compiler.compile(tree, "stdin", tokenizer.getLines(), input, chunk=compiled, showMismatches=mismatches, disabledWarnings=warnings, mode=mode, incremental=first)
if debugCompiler:
styledEcho fgCyan, "Compilation step:\n"
debugger.disassembleChunk(compiled, "stdin")
echo ""
serialized = serializer.loadBytes(serializer.dumpBytes(compiled, "stdin"))
if debugSerializer:
styledEcho fgCyan, "Serialization step: "
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch
stdout.styledWriteLine(fgBlue, "\t- Compilation date & time: ", fgYellow, fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss"))
stdout.styledWrite(fgBlue, &"\t- Constants segment: ")
if serialized.chunk.consts == compiled.consts:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
stdout.styledWrite(fgBlue, &"\t- Code segment: ")
if serialized.chunk.code == compiled.code:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
stdout.styledWrite(fgBlue, "\t- Line info segment: ")
if serialized.chunk.lines == compiled.lines:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
stdout.styledWrite(fgBlue, "\t- Functions segment: ")
if serialized.chunk.functions == compiled.functions:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
if not first:
vm.run(serialized.chunk, repl=true, breakpoints=breakpoints)
first = true
else:
vm.resume(serialized.chunk)
except LexingError:
print(LexingError(getCurrentException()))
except ParseError:
print(ParseError(getCurrentException()))
except CompileError:
print(CompileError(getCurrentException()))
except SerializationError:
var file = SerializationError(getCurrentException()).file
if file notin ["<string>", ""]:
file = relativePath(file, getCurrentDir())
stderr.styledWriteLine(fgRed, styleBright, "Error while (de-)serializing ", fgYellow, file, fgDefault, &": {getCurrentException().msg}")
quit(0)
]#
import std/strformat
proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[],
warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug, run: bool = true,
backend: PeonBackend = PeonBackend.Bytecode, output: string) =
warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug,
run: bool = true, backend: PeonBackend = PeonBackend.Bytecode, output: string) =
var
tokens: seq[Token] = @[]
tree: seq[Declaration] = @[]
@ -170,9 +51,9 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
serializer = newSerializer()
vm = newPeonVM()
input: string
f = f
tokenizer.fillSymbolTable()
try:
var f = f
if not fromString:
if not f.endsWith(".pn") and not f.endsWith(".pbc"):
f &= ".pn"
@ -258,22 +139,20 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
vm.run(serialized.chunk, breakpoints)
else:
discard
except LexingError:
print(LexingError(getCurrentException()))
except ParseError:
print(ParseError(getCurrentException()))
except CompileError:
print(CompileError(getCurrentException()))
except SerializationError:
var file = SerializationError(getCurrentException()).file
except LexingError as exc:
print(exc)
except ParseError as exc:
print(exc)
except CompileError as exc:
print(exc)
except SerializationError as exc:
var file = exc.file
if file notin ["<string>", ""]:
file = relativePath(file, getCurrentDir())
stderr.styledWriteLine(fgRed, styleBright, "Error while (de-)serializing ", fgYellow, file, fgDefault, &": {getCurrentException().msg}")
except IOError:
let exc = getCurrentException()
stderr.styledWriteLine(fgRed, styleBright, "Error while (de-)serializing ", fgYellow, file, fgDefault, &": {exc.msg}")
except IOError as exc:
stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, f, fgDefault, &": {exc.msg}")
except OSError:
let exc = getCurrentException()
except OSError as exc:
stderr.styledWriteLine(fgRed, styleBright, "Error while trying to read ", fgYellow, f, fgDefault, &": {exc.msg} ({osErrorMsg(osLastError())})",
fgRed, "[errno ", fgYellow, $osLastError(), fgRed, "]")
@ -290,7 +169,7 @@ when isMainModule:
var mismatches: bool = false
var mode: CompileMode = CompileMode.Debug
var run: bool = true
var backend: PeonBackend
var target: PeonBackend
var output: string = ""
for kind, key, value in optParser.getopt():
case kind:
@ -307,10 +186,10 @@ when isMainModule:
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, "invalid value for option 'mode' (valid options are: debug, release)")
quit()
of "help":
echo HELP_MESSAGE
echo HelpMessage
quit()
of "version":
echo PEON_VERSION_STRING
echo PeonVersionString
quit()
of "string":
file = key
@ -357,12 +236,12 @@ when isMainModule:
run = false
of "output":
output = value
of "backend":
of "target":
case value:
of "bytecode":
backend = PeonBackend.Bytecode
target = PeonBackend.Bytecode
of "c":
backend = PeonBackend.NativeC
target = PeonBackend.NativeC
of "debug-dump":
debugSerializer = true
of "debug-lexer":
@ -377,10 +256,10 @@ when isMainModule:
of "o":
output = value
of "h":
echo HELP_MESSAGE
echo HelpMessage
quit()
of "v":
echo PEON_VERSION_STRING
echo PeonVersionString
quit()
of "s":
file = key
@ -419,7 +298,6 @@ when isMainModule:
if breaks.len() == 0 and debugVM:
breaks.add(0)
if file == "":
echo "Sorry, the REPL is currently broken :("
#repl(warnings, mismatches, mode, breaks)
echo HelpMessage
else:
runFile(file, fromString, dump, breaks, warnings, mismatches, mode, run, backend, output)
runFile(file, fromString, dump, breaks, warnings, mismatches, mode, run, target, output)