Get rid of REPL + minor refactorings
This commit is contained in:
parent
45c5be7470
commit
919cc25579
22
README.md
22
README.md
|
@ -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
|
|
@ -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.}
|
||||
|
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
|
|
196
src/main.nim
196
src/main.nim
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue