Second part of VM lib transition

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-03-03 19:07:35 -05:00
parent 2b8663037f
commit 5ffca7bcf0
27 changed files with 4096 additions and 0 deletions

2
src/libvm/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
**/*.rs.bk

851
src/libvm/Cargo.lock generated Normal file
View File

@@ -0,0 +1,851 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bstr"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cactus"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cc"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfgrammar"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"vob 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-channel"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "doc-comment"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "error-chain"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "filetime"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getset"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-error 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "globset"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hermit-abi"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ignore"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "indexmap"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libvm"
version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfgrammar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lrlex 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lrpar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rerun_except 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"snafu 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lrlex"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lrpar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"typename 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lrpar"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cactus 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cfgrammar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lrtable 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"packedvec 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rmp-serde 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typename 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"vergen 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"vob 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lrtable"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfgrammar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"macro-attr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"newtype_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"sparsevec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"vob 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "macro-attr"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "newtype_derive"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "packedvec"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-error"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-error-attr 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-error-attr"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rerun_except"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ignore 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rmp"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rmp-serde"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rmp 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "snafu"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"snafu-derive 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "snafu-derive"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sparsevec"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"packedvec 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"vob 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-error 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn-mid"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "try_from"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typename"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"typename_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typename_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vergen"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"getset 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "version_check"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vob"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "walkdir"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536"
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "502ae1441a0a5adb8fbd38a5955a6416b9493e92b465de5e4a9bde6a539c2c48"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
"checksum cactus 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0713c9ecac2733e4c61a93157674eee620ba377d263714a6083d7a8be13468eb"
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum cfgrammar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20f2d944e00cc7ce8af4feb1604b0b35d846d9d44f526de3b6eb754190e9a901"
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
"checksum error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd"
"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
"checksum getset 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f62a139c59ae846c3964c392f12aac68f1997d1a40e9d3b40a89a4ab553e04a0"
"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
"checksum ignore 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e"
"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum lrlex 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "205bebfb37f228ad711fc22944328a3f2b9d89acb30590cbae6005c3aa2153dd"
"checksum lrpar 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5df95ed1526bb6a2d9e3890de679fc17178f5e68e930d921926d9e6e4e673638"
"checksum lrtable 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35afa92a7b9135277668b9a696ad9811238196f0b5fb8bda79a6f343fe3ef044"
"checksum macro-attr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00e51c6f0e2bf862b01b3d784fc32b02feb248a69062c51fb0b6d14cd526cc2a"
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum newtype_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8cd24d9f185bb7223958d8c1ff7a961b74b1953fd05dba7cc568a63b3861ec"
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
"checksum packedvec 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1fce532538ba443dbd7e9d0dd16e687cec205dc1c13fa4e6cb225f3405d85cdd"
"checksum proc-macro-error 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e7959c6467d962050d639361f7703b2051c43036d03493c36f01d440fdd3138a"
"checksum proc-macro-error-attr 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e4002d9f55991d5e019fb940a90e1a95eb80c24e77cb2462dd4dc869604d543a"
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1"
"checksum rerun_except 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f74370ce9660eea246c8c15aa4e30e836438a3ff9dc24af4ae1d3c6c6a0a3c1e"
"checksum rmp 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "0f10b46df14cf1ee1ac7baa4d2fbc2c52c0622a4b82fa8740e37bc452ac0184f"
"checksum rmp-serde 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c1ee98f14fe8b8e9c5ea13d25da7b2a1796169202c57a09d7288de90d56222b"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum snafu 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "546db9181bce2aa22ed883c33d65603b76335b4c2533a98289f54265043de7a1"
"checksum snafu-derive 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc75da2e0323f297402fd9c8fdba709bb04e4c627cbe31d19a2c91fc8d9f0e2"
"checksum sparsevec 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a182a1fc36753f8a2e3eea04cc3cd28065d2949cbda1e3a453cd183dace42bbb"
"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe43617218c0805c6eb37160119dc3c548110a67786da7218d1c6555212f073"
"checksum structopt-derive 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e79c80e0f4efd86ca960218d4e056249be189ff1c42824dcd9a7f51a56f0bd"
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
"checksum typename 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c255dd1af8cf5cfb95f062266201778080d215e86294dba14c47bf3137c55419"
"checksum typename_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c68acf2f6e8a32e2bad47e73ee177558583fb9dbb264a5c0569c7f9f80f79b0a"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum vergen 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "93fb2d57fbc535fcd45548c99b141d2d960995daaf04b864c4d9fe1ea011c819"
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
"checksum vob 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5430ea8977e2f0ed62cd37239cd713415022b240095c2f9187c32823015ae52f"
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

27
src/libvm/Cargo.toml Normal file
View File

@@ -0,0 +1,27 @@
[package]
name = "libvm"
version = "0.1.0"
authors = ["Alek Ratzloff <alekratz@gmail.com>"]
edition = "2018"
build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
structopt = "0.3"
bitflags = "1"
byteorder = "1"
lazy_static = "1"
snafu = "0.6.2"
cfgrammar = "0.6"
lrlex = "0.6"
lrpar = "0.6"
regex = "*"
[build-dependencies]
cfgrammar = "0.6"
lrlex = "0.6"
lrpar = "0.6"
rerun_except = "0.1"

18
src/libvm/build.rs Normal file
View File

@@ -0,0 +1,18 @@
use cfgrammar::yacc::YaccKind;
use lrlex::LexerBuilder;
use lrpar::{CTParserBuilder};
use rerun_except::rerun_except;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let lex_rule_ids_map = CTParserBuilder::new()
.yacckind(YaccKind::Grmtools)
.process_file_in_src("obj/syn/parser.y")?;
LexerBuilder::new()
.rule_ids_map(lex_rule_ids_map)
.process_file_in_src("obj/syn/lexer.l")?;
rerun_except(&[
"examples/*.asm",
"tests/*.asm",
]).unwrap();
Ok(())
}

73
src/libvm/src/addr.rs Normal file
View File

@@ -0,0 +1,73 @@
use std::{
cmp::Ordering,
fmt::{self, Formatter, LowerHex},
ops::{Add, AddAssign},
};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Addr(pub u64);
impl LowerHex for Addr {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
let Addr(v) = self;
LowerHex::fmt(v, fmt)
}
}
impl<T> Add<T> for Addr
where
T: Add<u64, Output = u64>,
u64: Add<T, Output = u64>,
{
type Output = Addr;
fn add(self, rhs: T) -> Self::Output {
Addr(self.0 + rhs)
}
}
macro_rules! impl_add_assign {
($ty:ty) => {
impl AddAssign<$ty> for Addr {
fn add_assign(&mut self, rhs: $ty) {
self.0 = self.0 + (rhs as u64);
}
}
}
}
impl_add_assign!(usize);
impl_add_assign!(u64);
macro_rules! impl_cmp {
($ty:ty) => {
impl PartialEq<$ty> for Addr {
fn eq(&self, other: &$ty) -> bool {
self.0 == (*other as u64)
}
}
impl PartialOrd<$ty> for Addr {
fn partial_cmp(&self, other: &$ty) -> Option<Ordering> {
let other = *other as u64;
self.0.partial_cmp(&other)
}
}
}
}
impl_cmp!(usize);
impl_cmp!(u64);
macro_rules! impl_from {
($ty:ty) => {
impl From<$ty> for Addr {
fn from(other: $ty) -> Self {
Addr(other as u64)
}
}
}
}
impl_from!(usize);
impl_from!(u64);

View File

@@ -0,0 +1,294 @@
use crate::{
error::*,
inst::*,
mem::MemCursor,
reg::*,
visit::*,
vm::{Addr, HalfWord, Word},
};
use std::io::Write;
const WIDTH: usize = 60;
pub struct Disassemble<'w, 'o> {
writer: &'w mut dyn Write,
cursor: MemCursor<'o>,
addr_offset: Addr,
}
impl<'w, 'o> Disassemble<'w, 'o> {
pub fn new(writer: &'w mut dyn Write, content: &'o [u8], addr_offset: Addr) -> Self {
Disassemble {
writer,
cursor: MemCursor::new(content),
addr_offset,
}
}
pub fn is_done(&self) -> bool {
self.cursor.position() >= (self.cursor.get_ref().len() as u64)
}
fn adv(&mut self) -> Result<()> {
// note the () - this explicitly clones the cursor
let op = self.cursor().next_u16()?;
let next = self.cursor.position() + (inst_len(op) as u64);
self.cursor.set_position(next);
Ok(())
}
fn write_addr(&mut self, addr: Addr) {
write!(self.writer, "{:06x} | ", self.addr_offset + addr).unwrap();
}
fn write_bytes(&mut self, bytes: &[u8]) {
for b in bytes {
write!(self.writer, "{:02x} ", b).unwrap();
}
}
fn write_inst_bytes(&mut self, op: InstOp) {
let len = inst_len(op);
let start = self.cursor.position() as usize;
let end = start + len;
let bytes = &self.cursor.get_ref()[start..end];
self.write_bytes(bytes);
}
fn write_r1_r2_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, r2: Reg) {
let len = inst_len(op);
let line_width = 6 + 3 + (3 * len);
let line_offset = WIDTH - line_width;
self.write_addr(addr);
self.write_inst_bytes(op);
let iname = inst_name(op).unwrap();
let r1name = reg_name(r1).unwrap().to_lowercase();
let r2name = reg_name(r2).unwrap().to_lowercase();
writeln!(
self.writer,
"{}| {:>10} %{} %{}",
" ".repeat(line_offset),
iname,
r1name,
r2name
)
.unwrap();
}
fn write_r1_inst(&mut self, addr: Addr, op: InstOp, r1: Reg) {
let line_width = 6 + 3 + (3 * inst_len(op));
let line_offset = WIDTH - line_width;
self.write_addr(addr);
self.write_inst_bytes(op);
let iname = inst_name(op).unwrap();
let r1name = reg_name(r1).unwrap().to_lowercase();
writeln!(
self.writer,
"{}| {:>10} %{}",
" ".repeat(line_offset),
iname,
r1name,
)
.unwrap();
}
fn write_r1_imm_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, imm: Word) {
let line_width = 6 + 3 + (3 * inst_len(op));
let line_offset = WIDTH - line_width;
self.write_addr(addr);
self.write_inst_bytes(op);
let iname = inst_name(op).unwrap();
let r1name = reg_name(r1).unwrap().to_lowercase();
writeln!(
self.writer,
"{}| {:>10} %{} {:#X}",
" ".repeat(line_offset),
iname,
r1name,
imm,
)
.unwrap();
}
}
impl VisitInst for Disassemble<'_, '_> {
type Out = ();
fn cursor(&self) -> MemCursor {
self.cursor.clone()
}
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), ADD, r1, r2);
self.adv()?;
Ok(())
}
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), MUL, r1, r2);
self.adv()?;
Ok(())
}
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), DIV, r1, r2);
self.adv()?;
Ok(())
}
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), MOD, r1, r2);
self.adv()?;
Ok(())
}
fn ineg(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), INEG, r1);
self.adv()?;
Ok(())
}
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), AND, r1, r2);
self.adv()?;
Ok(())
}
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), OR, r1, r2);
self.adv()?;
Ok(())
}
fn inv(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), INV, r1);
self.adv()?;
Ok(())
}
fn not(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), NOT, r1);
self.adv()?;
Ok(())
}
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), XOR, r1, r2);
self.adv()?;
Ok(())
}
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), SHL, r1, r2);
self.adv()?;
Ok(())
}
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), SHR, r1, r2);
self.adv()?;
Ok(())
}
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), CMPEQ, r1, r2);
self.adv()?;
Ok(())
}
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), CMPLT, r1, r2);
self.adv()?;
Ok(())
}
fn jmp(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), JMP, r1);
self.adv()?;
Ok(())
}
fn jz(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), JZ, r1);
self.adv()?;
Ok(())
}
fn jnz(&mut self, r1: Reg) -> Result<Self::Out> {
self.write_r1_inst(self.cursor.position(), JNZ, r1);
self.adv()?;
Ok(())
}
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), LOAD, r1, r2);
self.adv()?;
Ok(())
}
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), REGCOPY, r1, r2);
self.adv()?;
Ok(())
}
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out> {
self.write_r1_imm_inst(self.cursor.position(), STOREIMM64, r1, w1);
self.adv()?;
Ok(())
}
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out> {
self.write_r1_imm_inst(self.cursor.position(), STOREIMM32, r1, w1 as u64);
self.adv()?;
Ok(())
}
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), MEMCOPY, r1, r2);
self.adv()?;
Ok(())
}
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
self.write_r1_r2_inst(self.cursor.position(), STORE, r1, r2);
self.adv()?;
Ok(())
}
fn halt(&mut self) -> Result<Self::Out> {
let line_width = 6 + 3 + 3 + 3;
let line_offset = WIDTH - line_width;
self.write_addr(self.cursor.position());
self.write_inst_bytes(HALT);
writeln!(
self.writer,
"{}| {:>10}",
" ".repeat(line_offset),
"HALT",
).unwrap();
self.adv()?;
Ok(())
}
fn nop(&mut self) -> Result<Self::Out> {
let line_width = 6 + 3 + 3 + 3;
let line_offset = WIDTH - line_width;
self.write_addr(self.cursor.position());
self.write_inst_bytes(NOP);
writeln!(
self.writer,
"{}| {:>10}",
" ".repeat(line_offset),
"NOP",
).unwrap();
self.adv()?;
Ok(())
}
}

25
src/libvm/src/error.rs Normal file
View File

@@ -0,0 +1,25 @@
use crate::{inst::InstOp, reg::Reg, addr::*,};
use snafu::Snafu;
#[derive(Snafu, Debug, Clone)]
pub enum VmError {
#[snafu(display("illegal register: 0x{:02x}", reg))]
IllegalReg { reg: Reg },
#[snafu(display("memory address out of bounds: 0x{:016x}", addr))]
MemOutOfBounds { addr: Addr },
#[snafu(display("illegal instruction opcode: 0x{:04x}", op))]
IllegalOp { op: InstOp },
#[snafu(display("illegal destination specification: 0b{:08b}", spec))]
IllegalDestSpec { spec: u8 },
#[snafu(display("illegal source specification: 0b{:08b}", spec))]
IllegalSourceSpec { spec: u8 },
#[snafu(display("object to load spans too much memory"))]
ObjectTooLarge { object_size: usize, max_mem: usize },
}
pub type Result<T, E = VmError> = std::result::Result<T, E>;

8
src/libvm/src/flags.rs Normal file
View File

@@ -0,0 +1,8 @@
use bitflags::bitflags;
bitflags! {
pub struct Flags: u64 {
const HALT = 1;
const COMPARE = 1 << 1;
}
}

263
src/libvm/src/inst.rs Normal file
View File

@@ -0,0 +1,263 @@
use crate::{addr::Addr, reg::Reg};
macro_rules! instructions {
{
$($variant:ident = $value:expr),* $(,)?
} => {
$(
#[allow(dead_code)]
pub const $variant: InstOp = $value;
)*
pub fn inst_name(op: InstOp) -> Option<&'static str> {
match op {
$(
$value => Some(stringify!($variant)),
)*
_ => None,
}
}
};
}
pub type InstOp = u16;
instructions! {
ADD = 0x0000,
SUB = 0x0001,
MUL = 0x0002,
DIV = 0x0003,
IDIV = 0x0004,
MOD = 0x0005,
AND = 0x0006,
OR = 0x0007,
XOR = 0x0008,
SHL = 0x0009,
SHR = 0x000a,
INEG = 0x000b,
INV = 0x000c,
NOT = 0x000d,
CMPEQ = 0x1000,
CMPLT = 0x1001,
JMP = 0x1002,
JZ = 0x1003,
JNZ = 0x1004,
CALL = 0x2000,
RET = 0x2001,
PUSH = 0x2002,
POP = 0x2003,
MOV = 0x3000,
HALT = 0xF000,
NOP = 0xF001,
DUMP = 0xF002,
}
#[derive(Debug, Clone, Copy)]
pub enum Inst {
Add(Dest, Source),
Sub(Dest, Source),
Mul(Dest, Source),
Div(Dest, Source),
IDiv(Dest, Source),
Mod(Dest, Source),
And(Dest, Source),
Or(Dest, Source),
Xor(Dest, Source),
Shl(Dest, Source),
Shr(Dest, Source),
INeg(Dest, Source),
Inv(Dest, Source),
Not(Dest, Source),
CmpEq(Source, Source),
CmpLt(Source, Source),
Jmp(Source),
Jz(Source),
Jnz(Source),
Call(Source),
Ret,
Push(Source),
Pop(Dest),
Mov(Dest, Source),
Halt,
Nop,
Dump,
}
impl Inst {
pub fn op(&self) -> InstOp {
match self {
Inst::Add(_, _) => ADD,
Inst::Sub(_, _) => SUB,
Inst::Mul(_, _) => MUL,
Inst::Div(_, _) => DIV,
Inst::IDiv(_, _) => IDIV,
Inst::Mod(_, _) => MOD,
Inst::And(_, _) => AND,
Inst::Or(_, _) => OR,
Inst::Xor(_, _) => XOR,
Inst::Shl(_, _) => SHL,
Inst::Shr(_, _) => SHL,
Inst::INeg(_, _) => INEG,
Inst::Inv(_, _) => INV,
Inst::Not(_, _) => NOT,
Inst::CmpEq(_, _) => CMPEQ,
Inst::CmpLt(_, _) => CMPLT,
Inst::Jmp(_) => JMP,
Inst::Jz(_) => JZ,
Inst::Jnz(_) => JNZ,
Inst::Mov(_, _) => MOV,
Inst::Call(_) => CALL,
Inst::Ret => RET,
Inst::Push(_) => PUSH,
Inst::Pop(_) => POP,
Inst::Halt => HALT,
Inst::Nop => NOP,
Inst::Dump => DUMP,
}
}
pub fn len(&self) -> usize {
match self {
Inst::Add(dest, source)
| Inst::Sub(dest, source)
| Inst::Mul(dest, source)
| Inst::Div(dest, source)
| Inst::IDiv(dest, source)
| Inst::Mod(dest, source)
| Inst::And(dest, source)
| Inst::Or(dest, source)
| Inst::Xor(dest, source)
| Inst::Shl(dest, source)
| Inst::Shr(dest, source)
| Inst::INeg(dest, source)
| Inst::Inv(dest, source)
| Inst::Not(dest, source)
| Inst::Mov(dest, source) => { 3 + dest.len() + source.len() }
Inst::CmpEq(s1, s2)
| Inst::CmpLt(s1, s2) => { 3 + s1.len() + s2.len() }
Inst::Jmp(v)
| Inst::Jz(v)
| Inst::Jnz(v)
| Inst::Call(v)
| Inst::Push(v) => { 3 + v.len() }
Inst::Pop(v) => { 3 + v.len() }
Inst::Ret
| Inst::Halt
| Inst::Nop
| Inst::Dump => { 2 }
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Source {
Addr64(Addr),
Addr32(Addr),
Addr16(Addr),
Addr8(Addr),
RegAddr64(Reg),
RegAddr32(Reg),
RegAddr16(Reg),
RegAddr8(Reg),
Reg(Reg),
Imm(u64),
}
impl Source {
/// The length of this source in its instruction.
pub fn len(&self) -> usize {
match self {
Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8,
Source::RegAddr64(_) | Source::RegAddr32(_) | Source::RegAddr16(_) | Source::RegAddr8(_) => 1,
Source::Reg(_) => 1,
Source::Imm(_) => 8,
}
}
/// The length of the value that this source points to.
pub fn value_len(&self) -> usize {
match self {
Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => 8,
Source::Addr32(_) | Source::RegAddr32(_) => 4,
Source::Addr16(_) | Source::RegAddr16(_) => 2,
Source::Addr8(_) | Source::RegAddr8(_) => 1,
}
}
}
impl From<Dest> for Source {
fn from(other: Dest) -> Self {
match other {
Dest::Addr64(a) => Source::Addr64(a),
Dest::Addr32(a) => Source::Addr32(a),
Dest::Addr16(a) => Source::Addr16(a),
Dest::Addr8(a) => Source::Addr8(a),
Dest::RegAddr64(r) => Source::RegAddr64(r),
Dest::RegAddr32(r) => Source::RegAddr32(r),
Dest::RegAddr16(r) => Source::RegAddr16(r),
Dest::RegAddr8(r) => Source::RegAddr8(r),
Dest::Reg(r) => Source::Reg(r),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Dest {
Addr64(Addr),
Addr32(Addr),
Addr16(Addr),
Addr8(Addr),
RegAddr64(Reg),
RegAddr32(Reg),
RegAddr16(Reg),
RegAddr8(Reg),
Reg(Reg),
}
impl Dest {
/// The length of this destination in its instruction.
pub fn len(&self) -> usize {
match self {
Dest::Addr64(_) | Dest::Addr32(_) | Dest::Addr16(_) | Dest::Addr8(_) => 8,
Dest::RegAddr64(_) | Dest::RegAddr32(_) | Dest::RegAddr16(_) | Dest::RegAddr8(_) => 1,
Dest::Reg(_) => 1,
}
}
/// The length of the value that this destination points to.
pub fn value_len(&self) -> usize {
match self {
Dest::Addr64(_) | Dest::RegAddr64(_) | Dest::Reg(_) => 8,
Dest::Addr32(_) | Dest::RegAddr32(_) => 4,
Dest::Addr16(_) | Dest::RegAddr16(_) => 2,
Dest::Addr8(_) | Dest::RegAddr8(_) => 1,
}
}
}
// TODO : make this an enum
pub const DEST_ADDR64: u8 = 0b0000;
pub const DEST_ADDR32: u8 = 0b0001;
pub const DEST_ADDR16: u8 = 0b0010;
pub const DEST_ADDR8: u8 = 0b0011;
pub const DEST_REG_ADDR64: u8 = 0b0100;
pub const DEST_REG_ADDR32: u8 = 0b0101;
pub const DEST_REG_ADDR16: u8 = 0b0110;
pub const DEST_REG_ADDR8: u8 = 0b0111;
/* immediates - not used, invalid */
pub const DEST_REG: u8 = 0b1100;
pub const SOURCE_ADDR64: u8 = 0b0000;
pub const SOURCE_ADDR32: u8 = 0b0001;
pub const SOURCE_ADDR16: u8 = 0b0010;
pub const SOURCE_ADDR8: u8 = 0b0011;
pub const SOURCE_REG_ADDR64: u8 = 0b0100;
pub const SOURCE_REG_ADDR32: u8 = 0b0101;
pub const SOURCE_REG_ADDR16: u8 = 0b0110;
pub const SOURCE_REG_ADDR8: u8 = 0b0111;
pub const SOURCE_IMM64: u8 = 0b1000;
pub const SOURCE_IMM32: u8 = 0b1001;
pub const SOURCE_IMM16: u8 = 0b1010;
pub const SOURCE_IMM8: u8 = 0b1011;
pub const SOURCE_REG: u8 = 0b1100;

8
src/libvm/src/lib.rs Normal file
View File

@@ -0,0 +1,8 @@
pub mod addr;
pub mod error;
pub mod flags;
pub mod inst;
pub mod mem;
pub mod obj;
pub mod reg;
pub mod state;

278
src/libvm/src/mem.rs Normal file
View File

@@ -0,0 +1,278 @@
use crate::{addr::*, error::*, inst::*, reg::*};
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::io::Cursor;
pub struct MemCursor<T> {
cursor: Cursor<T>,
}
impl<T> MemCursor<T>
where Cursor<T>: ReadBytesExt,
T: AsRef<[u8]>
{
pub fn new(mem: T) -> Self {
MemCursor { cursor: Cursor::new(mem) }
}
pub fn position(&self) -> u64 {
self.cursor.position()
}
pub fn set_position<P: Into<Addr>>(&mut self, position: P) {
self.cursor.set_position((position.into()).0)
}
pub fn next_u8_unchecked(&mut self) -> u8 {
self.cursor.read_u8().unwrap()
}
pub fn next_u8(&mut self) -> Result<u8> {
self.check_addr(self.position())
.map(|_| self.next_u8_unchecked())
}
pub fn next_u16_unchecked(&mut self) -> u16 {
self.cursor.read_u16::<LE>().unwrap()
}
pub fn next_u16(&mut self) -> Result<u16> {
self.check_addr(self.position())
.map(|_| self.next_u16_unchecked())
}
pub fn next_u32_unchecked(&mut self) -> u32 {
self.cursor.read_u32::<LE>().unwrap()
}
pub fn next_u32(&mut self) -> Result<u32> {
self.check_addr(self.position())
.map(|_| self.next_u32_unchecked())
}
pub fn next_u64_unchecked(&mut self) -> u64 {
self.cursor.read_u64::<LE>().unwrap()
}
pub fn next_u64(&mut self) -> Result<u64> {
self.check_addr(self.position())
.map(|_| self.next_u64_unchecked())
}
pub fn next_addr(&mut self) -> Result<Addr> {
self.check_addr(self.position())
.map(|_| self.next_addr_unchecked())
}
pub fn next_addr_unchecked(&mut self) -> Addr {
Addr(self.next_u64_unchecked())
}
pub fn next_inst(&mut self) -> Result<Inst> {
let start = self.position();
let op = self.next_u16()?;
macro_rules! dest_source {
($variant:ident) => {{
let (d, s) = self.next_dest_source()?;
Ok(Inst::$variant(d, s))
}};
}
macro_rules! source_source {
($variant:ident) => {{
let (s1, s2) = self.next_source_source()?;
Ok(Inst::$variant(s1, s2))
}};
}
macro_rules! source {
($variant:ident) => {{
let spec = (self.next_u8()? & 0xF0) >> 4;
let source = self.next_source(spec)?;
Ok(Inst::$variant(source))
}};
}
macro_rules! dest {
($variant:ident) => {{
let spec = (self.next_u8()? & 0xF0) >> 4;
let dest = self.next_dest(spec)?;
Ok(Inst::$variant(dest))
}};
}
let inst = match op {
ADD => dest_source!(Add),
SUB => dest_source!(Sub),
MUL => dest_source!(Mul),
DIV => dest_source!(Div),
IDIV => dest_source!(IDiv),
MOD => dest_source!(Mod),
AND => dest_source!(And),
OR => dest_source!(Or),
XOR => dest_source!(Xor),
SHL => dest_source!(Shl),
SHR => dest_source!(Shr),
INEG => dest_source!(INeg),
INV => dest_source!(Inv),
NOT => dest_source!(Not),
CMPEQ => source_source!(CmpEq),
CMPLT => source_source!(CmpLt),
JMP => source!(Jmp),
JZ => source!(Jz),
JNZ => source!(Jnz),
CALL => source!(Call),
RET => Ok(Inst::Ret),
PUSH => source!(Push),
POP => dest!(Pop),
MOV => dest_source!(Mov),
HALT => Ok(Inst::Halt),
NOP => Ok(Inst::Nop),
DUMP => Ok(Inst::Dump),
_ => Err(VmError::IllegalOp { op }),
}?;
let end = self.position();
let len = (end - start) as usize;
assert_eq!(len, inst.len());
Ok(inst)
}
fn next_source_source(&mut self) -> Result<(Source, Source)> {
let spec = self.next_u8()?;
let s1_spec = (spec & 0xF0) >> 4;
let s2_spec = spec & 0x0F;
let s1 = self.next_source(s1_spec)?;
let s2 = self.next_source(s2_spec)?;
Ok((s1, s2))
}
fn next_dest_source(&mut self) -> Result<(Dest, Source)> {
let spec = self.next_u8()?;
let dest_spec = (spec & 0xF0) >> 4;
let source_spec = spec & 0x0F;
let dest = self.next_dest(dest_spec)?;
let source = self.next_source(source_spec)?;
Ok((dest, source))
}
fn next_dest(&mut self, spec: u8) -> Result<Dest> {
match spec {
DEST_ADDR64 => Ok(Dest::Addr64(self.next_addr()?)),
DEST_ADDR32 => Ok(Dest::Addr32(self.next_addr()?)),
DEST_ADDR16 => Ok(Dest::Addr16(self.next_addr()?)),
DEST_ADDR8 => Ok(Dest::Addr8(self.next_addr()?)),
DEST_REG_ADDR64 => Ok(Dest::RegAddr64(self.next_reg()?)),
DEST_REG_ADDR32 => Ok(Dest::RegAddr32(self.next_reg()?)),
DEST_REG_ADDR16 => Ok(Dest::RegAddr16(self.next_reg()?)),
DEST_REG_ADDR8 => Ok(Dest::RegAddr8(self.next_reg()?)),
DEST_REG => Ok(Dest::Reg(self.next_reg()?)),
_ => Err(VmError::IllegalDestSpec { spec }),
}
}
fn next_source(&mut self, spec: u8) -> Result<Source> {
match spec {
SOURCE_ADDR64 => Ok(Source::Addr64(self.next_addr()?)),
SOURCE_ADDR32 => Ok(Source::Addr32(self.next_addr()?)),
SOURCE_ADDR16 => Ok(Source::Addr16(self.next_addr()?)),
SOURCE_ADDR8 => Ok(Source::Addr8(self.next_addr()?)),
SOURCE_REG_ADDR64 => Ok(Source::RegAddr64(self.next_reg()?)),
SOURCE_REG_ADDR32 => Ok(Source::RegAddr32(self.next_reg()?)),
SOURCE_REG_ADDR16 => Ok(Source::RegAddr16(self.next_reg()?)),
SOURCE_REG_ADDR8 => Ok(Source::RegAddr8(self.next_reg()?)),
SOURCE_REG => Ok(Source::Reg(self.next_reg()?)),
SOURCE_IMM64 => Ok(Source::Imm(self.next_u64()?)),
SOURCE_IMM32 => Ok(Source::Imm(self.next_u32()? as u64)),
SOURCE_IMM16 => Ok(Source::Imm(self.next_u16()? as u64)),
SOURCE_IMM8 => Ok(Source::Imm(self.next_u8()? as u64)),
_ => Err(VmError::IllegalSourceSpec { spec }),
}
}
fn next_reg(&mut self) -> Result<Reg> {
let reg = self.next_u8()?;
if (reg as usize) >= NUM_REGS {
Err(VmError::IllegalReg { reg })
} else {
Ok(reg)
}
}
}
impl<T> MemCursor<T>
where T: AsRef<[u8]>
{
fn check_addr(&self, addr: u64) -> Result<()> {
if addr > (self.cursor.get_ref().as_ref().len() as u64) {
Err(VmError::MemOutOfBounds { addr: Addr(addr) })
} else {
Ok(())
}
}
}
impl<T> MemCursor<T>
where Cursor<T>: WriteBytesExt,
T: AsRef<[u8]>
{
pub fn write_u8_unchecked(&mut self, value: u8) {
self.cursor.write_u8(value).unwrap();
}
pub fn write_u8(&mut self, value: u8) -> Result<()> {
self.check_addr(self.position())
.map(|_| self.write_u8_unchecked(value))
}
pub fn write_u16_unchecked(&mut self, value: u16) {
self.cursor.write_u16::<LE>(value).unwrap();
}
pub fn write_u16(&mut self, value: u16) -> Result<()> {
self.check_addr(self.position())
.map(|_| self.write_u16_unchecked(value))
}
pub fn write_u32_unchecked(&mut self, value: u32) {
self.cursor.write_u32::<LE>(value).unwrap();
}
pub fn write_u32(&mut self, value: u32) -> Result<()> {
self.check_addr(self.position())
.map(|_| self.write_u32_unchecked(value))
}
pub fn write_u64_unchecked(&mut self, value: u64) {
self.cursor.write_u64::<LE>(value).unwrap();
}
pub fn write_u64(&mut self, value: u64) -> Result<()> {
self.check_addr(self.position())
.map(|_| self.write_u64_unchecked(value))
}
}
/*
////////////////////////////////////////////////////////////////////////////////
// Index impl
////////////////////////////////////////////////////////////////////////////////
impl<T: AsRef<[u8]>> Index<usize> for MemCursor<T> {
type Output = u8;
fn index(&self, addr: usize) -> &Self::Output {
self.mem.as_ref().index(addr)
}
}
impl<T: AsRef<[u8]>> Index<u64> for MemCursor<T> {
type Output = u8;
fn index(&self, addr: u64) -> &Self::Output {
self.index(addr as usize)
}
}
impl<T: AsRef<[u8]>> Index<Addr> for MemCursor<T> {
type Output = u8;
fn index(&self, addr: Addr) -> &Self::Output {
self.index(addr.0)
}
}
*/

View File

@@ -0,0 +1,360 @@
pub mod error;
pub mod session;
mod includes;
mod names;
use self::{error::*, session::AsmSession};
use crate::{
addr::Addr,
inst,
obj::{
obj::{self, Object},
syn::ast::*,
}
};
use byteorder::{WriteBytesExt, LE};
use std::{collections::HashMap, path::Path};
pub trait Asm {
type Out;
fn assemble(&self, asm: &mut AsmSession) -> Result<Self::Out>;
}
pub fn assemble_path(path: impl AsRef<Path>) -> Result<Object> {
let mut session = AsmSession::default();
session.include_path(path)?;
session.assemble()
}
impl Asm for Vec<&'_ Directive> {
type Out = obj::Object;
fn assemble(&self, asm: &mut AsmSession) -> Result<Self::Out> {
let sections = self
.iter()
.filter_map(|section| section.assemble(asm).transpose())
.collect::<Result<_>>()?;
Ok(obj::Object {
version: obj::OBJ_VERSION,
sections,
})
}
}
impl Asm for Directive {
type Out = Option<obj::Section>;
fn assemble(&self, asm: &mut AsmSession) -> Result<Self::Out> {
match self {
Directive::Data(section) => Ok(Some(obj::Section::Data(section.assemble(asm)?))),
Directive::Meta(section) => section.assemble(asm).map(Some),
Directive::Include(_) => { Ok(None) }
}
}
}
impl Asm for DataSection {
type Out = obj::DataSection;
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
let names = names::get_section_names(self)?;
session.name_stack.push(names);
let section_len = self.len() as u64;
let (start, end) = match self.org {
SectionOrg::Start(start) => (start, start + (section_len as u64)),
SectionOrg::StartEnd(start, end) => (start, end),
};
session.pos = Addr(start);
if start > end {
return Err(AsmError::StartGreaterThanEnd { start, end });
}
let len = end - start - 1;
if len > section_len {
return Err(AsmError::SectionTooShort {
section_end: end,
section_size: start + section_len,
});
}
let mut contents = Vec::with_capacity(section_len as usize);
for line in self.lines.iter() {
contents.extend(line.assemble(session)?);
session.pos += line.len();
}
assert_eq!(
contents.len() as u64,
section_len,
"in section {}",
self.name
);
session.name_stack.pop();
Ok(obj::DataSection {
name: self.name.clone(),
start,
len: section_len,
contents,
})
}
}
impl Asm for MetaSection {
type Out = obj::Section;
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
let mut entries = HashMap::new();
for line in self.lines.iter() {
if entries.contains_key(&line.name) {
return Err(AsmError::DuplicateMetaName {
name: line.name.to_string(),
});
}
let value = match &line.value {
Value::Int(i) => *i,
Value::Name(s) => session.lookup_name(s.as_str())
.ok_or_else(|| AsmError::UnknownName { name: s.to_string() })?.addr.0,
Value::Reg(_) | Value::Here | Value::Addr(_, _) => {
return Err(AsmError::IllegalMetaValue {
name: line.name.to_string(),
value: line.value.clone(),
})
} // TODO :
// * deref constexpr?
// * pre-startup static init?
};
entries.insert(line.name.to_string(), value);
}
Ok(obj::Section::Meta(obj::MetaSection { entries }))
}
}
impl Asm for DataLine {
type Out = Vec<u8>;
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
match self {
DataLine::ValueDef(v) => v.assemble(session),
DataLine::Inst(i) => i.assemble(session),
DataLine::Export(_) | DataLine::Label(_) => Ok(Vec::new()),
}
}
}
impl Asm for ValueDef {
type Out = Vec<u8>;
fn assemble(&self, _: &mut AsmSession) -> Result<Self::Out> {
match self {
ValueDef::Int(x, s) => Ok(x.to_le_bytes().iter().copied().take(s.len()).collect()),
ValueDef::String(s) => {
let bytes = s.bytes();
let mut out = s.len().to_le_bytes().to_vec();
out.extend(bytes);
Ok(out)
}
ValueDef::ZString(z) => {
let bytes = z.bytes();
let mut out = z.len().to_le_bytes().to_vec();
out.extend(bytes);
Ok(out)
}
}
}
}
impl Asm for Inst {
type Out = Vec<u8>;
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
let len = self.len();
macro_rules! map_inst {
($op:expr, $dest:expr, $source:expr) => {{
let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>($op).unwrap();
let dest = $dest;
let dest_encoding =
dest.dest_encoding()
.ok_or_else(|| AsmError::IllegalDestValue {
value: dest.clone(),
})?;
let source = $source;
let source_encoding = source.source_encoding();
bytes
.write_u8((dest_encoding << 4) | source_encoding)
.unwrap();
bytes.extend(dest.assemble(session)?);
bytes.extend(source.assemble(session)?);
assert_eq!(
self.len(),
bytes.len(),
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
stringify!($op),
self,
bytes
);
Ok(bytes)
}};
($op:expr, $source:expr) => {{
let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>($op).unwrap();
let source = $source;
let source_encoding = source.source_encoding() << 4;
bytes.write_u8(source_encoding).unwrap();
bytes.extend(source.assemble(session)?);
assert_eq!(
self.len(),
bytes.len(),
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
stringify!($op),
self,
bytes
);
Ok(bytes)
}};
($op:expr) => {{
let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>($op).unwrap();
assert_eq!(
self.len(),
bytes.len(),
"instruction size mismatch in {} instruction - {:?} produces these bytes {:?}",
stringify!($op),
self,
bytes
);
Ok(bytes)
}};
}
match self {
Inst::Add(v1, v2) => map_inst!(inst::ADD, v1, v2),
Inst::Sub(v1, v2) => map_inst!(inst::SUB, v1, v2),
Inst::Mul(v1, v2) => map_inst!(inst::MUL, v1, v2),
Inst::Div(v1, v2) => map_inst!(inst::DIV, v1, v2),
Inst::IDiv(v1, v2) => map_inst!(inst::IDIV, v1, v2),
Inst::Mod(v1, v2) => map_inst!(inst::MOD, v1, v2),
Inst::And(v1, v2) => map_inst!(inst::AND, v1, v2),
Inst::Or(v1, v2) => map_inst!(inst::OR, v1, v2),
Inst::Xor(v1, v2) => map_inst!(inst::XOR, v1, v2),
Inst::Shl(v1, v2) => map_inst!(inst::SHL, v1, v2),
Inst::Shr(v1, v2) => map_inst!(inst::SHR, v1, v2),
Inst::INeg(v1, v2) => map_inst!(inst::INEG, v1, v2),
Inst::Inv(v1, v2) => map_inst!(inst::INV, v1, v2),
Inst::Not(v1, v2) => map_inst!(inst::NOT, v1, v2),
// TODO/BUG: CmpEq and CmpLt both take two sources instead of a source and destination
Inst::CmpEq(v1, v2) => map_inst!(inst::CMPEQ, v1, v2),
Inst::CmpLt(v1, v2) => map_inst!(inst::CMPLT, v1, v2),
Inst::Jmp(v) => map_inst!(inst::JMP, v),
Inst::Jz(v) => map_inst!(inst::JZ, v),
Inst::Jnz(v) => map_inst!(inst::JNZ, v),
Inst::Call(v) => map_inst!(inst::CALL, v),
Inst::Ret => map_inst!(inst::RET),
Inst::Push(v) => map_inst!(inst::PUSH, v),
Inst::Pop(dest) => {
let mut bytes = Vec::with_capacity(len);
bytes.write_u16::<LE>(inst::POP).unwrap();
let dest_encoding = dest.source_encoding() << 4;
bytes.write_u8(dest_encoding).unwrap();
bytes.extend(dest.assemble(session)?);
assert_eq!(
self.len(),
bytes.len(),
"instruction size mismatch in inst::PUSH instruction - {:?} produces these bytes {:?}",
self,
bytes
);
Ok(bytes)
}
Inst::Mov(v1, v2) => map_inst!(inst::MOV, v1, v2),
Inst::Halt => map_inst!(inst::HALT),
Inst::Nop => map_inst!(inst::NOP),
Inst::Dump => map_inst!(inst::DUMP),
}
}
}
impl Asm for Value {
type Out = Vec<u8>;
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
match self {
Value::Int(i) => Ok(i.to_le_bytes().to_vec()),
Value::Reg(r) => Ok(vec![*r]),
Value::Name(name) => {
let value = session.lookup_name(name.as_str())
.ok_or_else(|| AsmError::UnknownName { name: name.to_string() })?;
Ok(value.addr.0.to_le_bytes().to_vec())
}
Value::Here => Ok(session.pos.0.to_le_bytes().to_vec()),
Value::Addr(v, _) => {
if let Value::Addr(_, _) = &**v {
// double deref is not allowed
todo!()
} else {
v.assemble(session)
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_inst_len() {
let mut session = AsmSession::default();
//asm.names
//.push(vec![("test".to_string(), Addr(0u64))].into_iter().collect());
macro_rules! assert_len {
($inst:expr) => {{
let inst = $inst;
let asm_size = $inst.assemble(&mut session).unwrap().len();
assert_eq!(inst.len(), asm_size, "Instruction {:?}.len() indicates it should be {} bytes long but was assembled as {} bytes", inst, inst.len(), asm_size);
}}
}
use Inst::*;
let dummy_dests = &[
Value::Reg(0),
Value::Addr(Box::new(Value::Reg(0)), IntSize::U8),
Value::Addr(Box::new(Value::Here), IntSize::U16),
//Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32),
Value::Addr(Box::new(Value::Int(0)), IntSize::U64),
];
let dummy_sources = &[
Value::Int(0),
Value::Reg(0),
//Value::Name("test".to_string()),
Value::Here,
Value::Addr(Box::new(Value::Reg(0)), IntSize::U8),
Value::Addr(Box::new(Value::Here), IntSize::U16),
//Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32),
Value::Addr(Box::new(Value::Int(0)), IntSize::U32),
];
for v1 in dummy_dests {
for v2 in dummy_sources {
assert_len!(Add(v1.clone(), v2.clone()));
assert_len!(Sub(v1.clone(), v2.clone()));
assert_len!(Mul(v1.clone(), v2.clone()));
assert_len!(Div(v1.clone(), v2.clone()));
assert_len!(Mod(v1.clone(), v2.clone()));
assert_len!(And(v1.clone(), v2.clone()));
assert_len!(Or(v1.clone(), v2.clone()));
assert_len!(Xor(v1.clone(), v2.clone()));
assert_len!(Shl(v1.clone(), v2.clone()));
assert_len!(Shr(v1.clone(), v2.clone()));
assert_len!(INeg(v1.clone(), v2.clone()));
assert_len!(Inv(v1.clone(), v2.clone()));
assert_len!(Not(v1.clone(), v2.clone()));
assert_len!(Mov(v1.clone(), v2.clone()));
// TODO more length tests
}
}
}
}

View File

@@ -0,0 +1,114 @@
use crate::obj::syn::ast::*;
use snafu::Snafu;
use std::path::PathBuf;
pub type LexError = lrpar::LexError;
pub type ParseError = lrpar::ParseError<u32>;
pub type LexParseError = lrpar::LexParseError<u32>;
#[derive(Debug, Snafu)]
pub enum AsmError {
#[snafu(display("unknown name: {}", name))]
UnknownName {
name: String,
},
#[snafu(display("unknown export name: {}", name))]
UnknownExport {
name: String,
},
#[snafu(display("duplicate label definition: {}", name))]
DuplicateLabel {
name: String,
},
#[snafu(display("duplicate meta entry name: {}", name))]
DuplicateMetaName {
name: String,
},
#[snafu(display("illegal meta value for entry name {}: {:?}", name, value))]
IllegalMetaValue {
name: String,
value: Value,
},
#[snafu(display("duplicate exported name: {}", name))]
DuplicateExport {
name: String,
},
#[snafu(display("section start ({:#x}) is greater than end ({:#x})", start, end))]
StartGreaterThanEnd {
start: u64,
end: u64,
},
#[snafu(display(
"section end ({:#x}) too short for section content size ({:#x})",
section_end,
section_size
))]
SectionTooShort {
section_end: u64,
section_size: u64,
},
#[snafu(display("illegal instruction destination value: {:?}", value))]
IllegalDestValue {
value: Value,
},
#[snafu(display("deref of a deref value is not allowed"))]
DoubleDeref {
value: Value,
},
// TODO(asm) : Path error wrapper for assembling things
#[snafu(display("could not read path: {}", path.display()))]
BadPath {
path: PathBuf,
},
Syntax {
source: SyntaxError,
},
}
#[derive(Debug, Snafu)]
pub enum SyntaxError {
Lex { source: LexError },
Parse { source: ParseError },
Multi { errors: Vec<LexParseError> },
}
impl From<LexError> for SyntaxError {
fn from(source: LexError) -> Self {
SyntaxError::Lex { source }
}
}
impl From<ParseError> for SyntaxError {
fn from(source: ParseError) -> Self {
SyntaxError::Parse { source }
}
}
impl From<Vec<LexParseError>> for SyntaxError {
fn from(errors: Vec<LexParseError>) -> Self {
SyntaxError::Multi { errors }
}
}
impl From<LexParseError> for SyntaxError {
fn from(source: LexParseError) -> Self {
match source {
LexParseError::LexError(e) => SyntaxError::Lex { source: e },
LexParseError::ParseError(e) => SyntaxError::Parse { source: e },
}
}
}
pub type Result<T, E = AsmError> = std::result::Result<T, E>;

View File

@@ -0,0 +1,68 @@
use crate::obj::{
assemble::{error::*, session::AsmSession, Asm},
syn::{ast::Directive, lexer, parser},
};
use std::{path::PathBuf, rc::Rc};
#[derive(Debug, Clone)]
pub struct GetIncludes {
path: PathBuf,
}
impl GetIncludes {
pub fn assemble_from_path(path: PathBuf, session: &mut AsmSession) -> Result<()> {
let path = path
.canonicalize()
.map_err(|_| AsmError::BadPath { path })?;
GetIncludes { path }.assemble(session)
}
}
impl Asm for GetIncludes {
type Out = ();
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
assert!(self.path.is_absolute());
if session.includes.contains_key(&self.path) {
return Ok(());
}
let text = std::fs::read_to_string(&self.path).map_err(|_| AsmError::BadPath {
path: self.path.clone(),
})?;
let lexerdef = lexer::lexerdef();
let lexer = lexerdef.lexer(&text);
let (res, errors) = parser::parse(&lexer);
if !errors.is_empty() {
return Err(AsmError::Syntax {
source: errors.into(),
});
}
// insert a dummy AST in the includes and replace it when we're done with the actual AST
Rc::get_mut(&mut session.includes)
.unwrap()
.insert(self.path.clone(), Default::default());
session.include_stack.push(self.path.clone());
let ast = res.unwrap();
for directive in ast.iter() {
if let Directive::Include(include_path) = directive {
GetIncludes::assemble_from_path(PathBuf::from(include_path), session)?;
}
}
session.include_stack.pop();
let dummy = Rc::get_mut(&mut session.includes)
.unwrap()
.insert(self.path.clone(), ast)
.expect("ast was removed after its inclusion (why did you do that?)");
assert!(
dummy.is_empty(),
"ast was modified after its inclusion (why did you do that?)"
);
Ok(())
}
}

View File

@@ -0,0 +1,104 @@
use crate::{
addr::Addr,
obj::{
assemble::{
session::AsmSession,
error::*,
},
syn::ast::{DataSection, DataLine, Directive},
},
};
use std::{collections::{HashMap, HashSet}, rc::Rc};
// TODO(asm) make custom Names type that has "merge" that will catch errors with duplicate names
pub type Names = HashMap<String, Name>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Name {
pub name: String,
pub addr: Addr,
pub export: bool,
}
pub fn get_section_names(section: &DataSection) -> Result<Names> {
let mut pos = Addr(section.org.start());
let mut names = HashMap::new();
let mut exports = HashSet::new();
// This isn't immediately straightforward in code, so this is what's happening.
//
// A name may be specified exactly once. It is added to the "names" mapping. If the name is
// specified again, it is a duplicate error and handled as such. A name may be flagged as
// being exported.
//
// Exports are gathered at the beginning into a set. Afterwards, as name definitions
// are gathered, exports are removed from their set if they exist. Since duplicate names
// cause an error, export names will only be removed once.
//
// At the end of name gathering, if any exports have not been removed, then we know those
// are exports whose names are undefined and we can return an UnknownExport error.
// get exported names
for line in section.lines.iter() {
if let DataLine::Export(name) = line {
exports.insert(name);
}
}
// get names
for line in section.lines.iter() {
if let DataLine::Label(name) = line {
if names.contains_key(name) {
return Err(AsmError::DuplicateLabel { name: name.clone() });
}
let export = exports.remove(name);
names.insert(name.clone(), Name {
name: name.clone(),
addr: pos,
export,
});
}
pos += line.len();
}
// all exports map 1:1 with names
if exports.is_empty() {
Ok(names)
} else {
Err(AsmError::UnknownExport { name: exports.iter().next().unwrap().to_string() })
}
}
pub fn get_exports(session: &mut AsmSession) -> Result<Names> {
let includes = Rc::clone(&session.includes);
let mut all_exports = Vec::new();
// get *all* exports first
for (_, ast) in includes.iter() {
for directive in ast.iter() {
if let Directive::Data(section) = directive {
let names: HashMap<_, _> = get_section_names(section)?
.into_iter()
.filter(|(_, name)| name.export)
.collect();
all_exports.push(names);
}
}
}
let mut exports = HashSet::new();
// make a set of all export names, erroring on duplicate export
for name_map in all_exports.iter() {
let names_set: HashSet<_> = name_map.keys().collect();
if let Some(dupe) = exports.intersection(&names_set).next() {
return Err(AsmError::DuplicateExport { name: dupe.to_string() });
}
exports.extend(names_set);
}
// NOTE: this can probably be done with a fancy combinator chain
Ok(all_exports.into_iter()
.fold(Names::new(), |mut acc, val| { acc.extend(val); acc }))
}

View File

@@ -0,0 +1,72 @@
use crate::{
addr::Addr,
obj::{
assemble::{
Asm,
includes::GetIncludes,
names::{self, Name, Names},
error::*,
},
obj::Object,
syn::ast::Ast,
},
};
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
rc::Rc,
};
/// A shared session for the assembler.
#[derive(Debug, Default)]
pub struct AsmSession {
pub (in super) includes: Rc<BTreeMap<PathBuf, Ast>>,
pub (in super) include_search_paths: Vec<PathBuf>,
pub (in super) include_stack: Vec<PathBuf>,
pub (in super) name_stack: Vec<Names>,
pub (in super) pos: Addr,
}
impl AsmSession {
pub fn assemble(&mut self) -> Result<Object> {
let includes = Rc::clone(&self.includes);
let sections: Vec<_> = includes.iter()
.flat_map(|(_, ast)| ast)
.collect();
sections.assemble(self)
}
pub fn include_path(&mut self, path: impl AsRef<Path>) -> Result<()> {
self.include_stack.clear();
let path = path.as_ref().to_path_buf();
GetIncludes::assemble_from_path(path, self)?;
let exports = names::get_exports(self)?;
// TODO(asm) - merge exports
self.name_stack.push(exports);
Ok(())
}
pub (in super) fn current_include_path(&self) -> Option<&Path> {
self.include_stack.last().map(PathBuf::as_path)
}
pub (in super) fn resolve_include_path(&self, path: impl AsRef<Path>) -> Option<PathBuf> {
let path = path.as_ref();
self.current_include_path()
.and_then(|last_path| last_path.parent())
.map(|last_dir| last_dir.join(path))
.or_else(|| self.include_search_paths
.iter()
.filter_map(|include| include.join(path).canonicalize().ok())
.next())
}
pub fn lookup_name(&self, name: &str) -> Option<&Name> {
self.name_stack
.iter()
.rev()
.filter_map(|names| names.get(name))
.next()
}
}

View File

@@ -0,0 +1,45 @@
use snafu::Snafu;
use std::{fmt::Debug, io};
#[derive(Debug, Snafu)]
pub enum ParseError {
#[snafu(display("IO error: {}", source))]
Io { source: io::Error },
#[snafu(display("wrong magic number"))]
WrongMagic,
#[snafu(display("unknown section kind: 0x{:02x}", kind))]
UnknownSectionKind { kind: u8 },
#[snafu(display("invalid UTF-8 string: {}", source))]
InvalidUtf8String { source: std::string::FromUtf8Error },
#[snafu(display("duplicate symbol name: {}", name))]
DuplicateName { name: String },
#[snafu(display("duplicate exported symbol name: {}", name))]
DuplicateExportName { name: String },
}
macro_rules! into_parse_error {
(
$($type:ty : $variant:ident),* $(,)?
) => {
$(
impl From<$type> for ParseError {
fn from(other: $type) -> Self {
ParseError::$variant { source: other }
}
}
)*
}
}
into_parse_error! {
io::Error: Io,
std::string::FromUtf8Error: InvalidUtf8String,
}
pub type Result<T, E = ParseError> = std::result::Result<T, E>;

4
src/libvm/src/obj/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod assemble;
pub mod error;
pub mod obj;
pub mod syn;

269
src/libvm/src/obj/obj.rs Normal file
View File

@@ -0,0 +1,269 @@
use crate::obj::error::{ParseError, Result};
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
use std::{
collections::HashMap,
convert::{TryFrom, TryInto},
fmt::Debug,
io::{Cursor, Read, Write},
};
pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11;
pub const OBJ_VERSION: u32 = 0;
const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4
#[derive(Debug, Clone, PartialEq)]
pub struct Object {
pub version: u32,
pub sections: Vec<Section>,
}
impl Object {
pub fn to_bytes(&self) -> Vec<u8> {
let mut cursor = Cursor::new(Vec::new());
cursor.write_u64::<LE>(MAGIC).unwrap();
cursor.write_u32::<LE>(OBJ_VERSION).unwrap();
cursor.write_u32::<LE>(self.sections.len() as u32).unwrap();
for section in self.sections.iter() {
cursor.write(&section.to_bytes()).unwrap();
}
cursor.into_inner()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let mut cursor = Cursor::new(bytes);
let magic = cursor.read_u64::<LE>()?;
if magic != MAGIC {
return Err(ParseError::WrongMagic);
}
let version = cursor.read_u32::<LE>()?;
let section_count = cursor.read_u32::<LE>()?;
let mut sections = Vec::new();
for _ in 0..section_count {
let start = cursor.position() as usize;
let section = Section::from_bytes(&bytes[start..])?;
cursor.set_position((start + section.len()) as u64);
sections.push(section);
}
Ok(Object { version, sections })
}
pub fn virtual_len(&self) -> usize {
self.sections
.iter()
.map(|s| match s {
Section::Data(DataSection { start, len, .. }) => (start + len) as usize,
Section::Meta { .. } => 0,
})
.max()
.unwrap_or(0)
}
}
macro_rules! section_kind {
(
pub enum $enum_name:ident {
$($name:ident = $value:expr),* $(,)?
}
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum $enum_name {
$($name = $value),*
}
impl TryFrom<u8> for SectionKind {
type Error = ParseError;
fn try_from(other: u8) -> std::result::Result<Self, Self::Error> {
match other {
$(
$value => Ok($enum_name::$name),
)*
_ => Err(ParseError::UnknownSectionKind { kind: other }),
}
}
}
impl From<SectionKind> for u8 {
fn from(other: SectionKind) -> Self {
match other {
$(
$enum_name::$name => $value,
)*
}
}
}
};
}
section_kind! {
pub enum SectionKind {
Data = 0x00,
Meta = 0xFF,
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Section {
Data(DataSection),
Meta(MetaSection),
}
impl Section {
pub fn len(&self) -> usize {
match self {
Section::Data(s) => { 1 + 8 + s.len() },
Section::Meta(s) => { 1 + 8 + s.len() },
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut cursor = Cursor::new(Vec::new());
let bytes = match self {
Section::Data(s) => {
cursor.write_u8(SectionKind::Data.into()).unwrap();
s.to_bytes()
}
Section::Meta(s) => {
cursor.write_u8(SectionKind::Meta.into()).unwrap();
s.to_bytes()
},
};
cursor.write_u64::<LE>(bytes.len() as u64).unwrap();
cursor.write(&bytes).unwrap();
cursor.into_inner()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let mut cursor = Cursor::new(bytes);
let kind: SectionKind = cursor.read_u8()?.try_into()?;
let len = cursor.read_u64::<LE>()?;
let start = cursor.position() as usize;
let end = start + len as usize;
let bytes = &cursor.get_ref()[start..end];
match kind {
SectionKind::Data => Ok(Section::Data(DataSection::from_bytes(bytes)?)),
SectionKind::Meta => Ok(Section::Meta(MetaSection::from_bytes(bytes)?)),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DataSection {
pub name: String,
pub start: u64,
pub len: u64,
pub contents: Vec<u8>,
}
impl DataSection {
pub fn len(&self) -> usize {
2 + self.name.as_bytes().len() + 8 + 8 + self.contents.len()
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut cursor = Cursor::new(Vec::new());
assert!(self.name.len() < u16::max_value() as usize);
cursor.write_u16::<LE>(self.name.len() as u16).unwrap();
cursor.write(self.name.as_bytes()).unwrap();
cursor.write_u64::<LE>(self.start).unwrap();
cursor.write_u64::<LE>(self.len).unwrap();
cursor.write(&self.contents).unwrap();
cursor.into_inner()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let mut cursor = Cursor::new(bytes);
let name_len = cursor.read_u16::<LE>()? as usize;
let name_start = cursor.position() as usize;
let name_end = name_start + name_len;
let name_bytes = &bytes[name_start .. name_end];
let name_string = String::from_utf8(name_bytes.to_vec())?;
cursor.set_position(name_end as u64);
let start = cursor.read_u64::<LE>()?;
let len = cursor.read_u64::<LE>()?;
let contents = &bytes[cursor.position() as usize..];
Ok(DataSection {
name: name_string,
start,
len,
contents: From::from(contents),
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct MetaSection {
pub entries: HashMap<String, u64>,
}
impl MetaSection {
pub fn len(&self) -> usize {
8 + self.entries.iter()
.map(|(k, _)| 8 + k.as_bytes().len() + 8)
.sum::<usize>()
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut cursor = Cursor::new(Vec::new());
cursor.write_u64::<LE>(self.entries.len() as u64).unwrap();
for (k, v) in self.entries.iter() {
let key_len = k.as_bytes().len();
cursor.write_u64::<LE>(key_len as u64).unwrap();
cursor.write(k.as_bytes()).unwrap();
cursor.write_u64::<LE>(*v).unwrap();
}
cursor.into_inner()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let mut cursor = Cursor::new(bytes);
let entry_count = cursor.read_u64::<LE>()?;
let mut entries = HashMap::new();
for _ in 0..entry_count {
// key
let key_len = cursor.read_u64::<LE>()?;
let mut key_bytes = vec![0u8; key_len as usize];
cursor.read_exact(&mut key_bytes)?;
let key = String::from_utf8(key_bytes)?;
// value
let value = cursor.read_u64::<LE>()?;
entries.insert(key, value);
}
Ok(MetaSection { entries })
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_to_from_bytes() {
let obj = Object {
version: OBJ_VERSION,
sections: vec![
Section::Data(DataSection {
name: "data".to_string(),
start: 0,
len: 16,
contents: vec!(0u8; 16),
}),
Section::Meta(MetaSection {
entries: Default::default(),
})
],
};
let obj_bytes = obj.to_bytes();
let converted = Object::from_bytes(&obj_bytes).unwrap();
assert_eq!(obj, converted);
}
}

View File

@@ -0,0 +1,255 @@
use crate::{
inst,
reg::Reg,
};
pub type Ast = Vec<Directive>;
#[derive(Debug, Clone)]
pub enum Directive {
Meta(MetaSection),
Data(DataSection),
Include(String),
}
#[derive(Debug, Clone)]
pub struct MetaSection {
pub lines: Vec<MetaLine>,
}
#[derive(Debug, Clone)]
pub struct MetaLine {
pub name: String,
pub value: Value,
}
#[derive(Debug, Clone)]
pub struct DataSection {
pub name: String,
pub org: SectionOrg,
pub lines: Vec<DataLine>,
}
impl DataSection {
pub fn exports(&self) -> impl Iterator<Item=&str> {
self.lines.iter()
.filter_map(|line| if let DataLine::Export(s) = line {
Some(s.as_str())
} else {
None
})
}
pub fn len(&self) -> usize {
self.lines.iter()
.map(DataLine::len)
.sum()
}
}
#[derive(Debug, Clone)]
pub enum SectionOrg {
Start(u64),
StartEnd(u64, u64),
}
impl SectionOrg {
pub fn start(&self) -> u64 {
match self {
SectionOrg::Start(start) | SectionOrg::StartEnd(start, _) => *start,
}
}
}
#[derive(Debug, Clone)]
pub enum DataLine {
ValueDef(ValueDef),
Inst(Inst),
Export(String),
Label(String),
}
impl DataLine {
pub fn len(&self) -> usize {
match self {
DataLine::ValueDef(v) => v.len(),
DataLine::Inst(i) => i.len(),
DataLine::Export(_) | DataLine::Label(_) => 0,
}
}
}
#[derive(Debug, Clone)]
pub enum ValueDef {
Int(u64, IntSize),
String(String),
ZString(String),
}
impl ValueDef {
pub fn len(&self) -> usize {
match self {
ValueDef::Int(_, s) => s.len(),
ValueDef::String(s) => 8 + s.as_bytes().len(),
ValueDef::ZString(s) => s.as_bytes().len() + 1,
}
}
}
#[derive(Debug, Clone)]
pub enum Value {
// TODO : immediate int sizes
// Int(u64, IntSize)
Int(u64),
Reg(Reg),
Name(String),
Here,
Addr(Box<Value>, IntSize),
}
impl Value {
pub fn len(&self) -> usize {
match self {
Value::Int(_) => 8,
Value::Reg(_) => 1,
Value::Name(_) => 8,
Value::Here => 8,
Value::Addr(v, _) => v.len(),
}
}
pub fn dest_encoding(&self) -> Option<u8> {
match self {
Value::Int(_) | Value::Name(_) | Value::Here => None,
Value::Reg(_) => Some(inst::DEST_REG),
// TODO : check reg vs int value, and use dest_reg_addr8/16/32/64 values
Value::Addr(v, size) => {
if let Value::Reg(_) = &**v {
match size {
IntSize::U64 => Some(inst::DEST_REG_ADDR64),
IntSize::U32 => Some(inst::DEST_REG_ADDR32),
IntSize::U16 => Some(inst::DEST_REG_ADDR16),
IntSize::U8 => Some(inst::DEST_REG_ADDR8),
}
} else {
match size {
IntSize::U64 => Some(inst::DEST_ADDR64),
IntSize::U32 => Some(inst::DEST_ADDR32),
IntSize::U16 => Some(inst::DEST_ADDR16),
IntSize::U8 => Some(inst::DEST_ADDR8),
}
}
}
}
}
pub fn source_encoding(&self) -> u8 {
match self {
Value::Int(_) => inst::SOURCE_IMM64,
Value::Reg(_) => inst::SOURCE_REG,
// TODO : check reg vs int value, and use source_reg_addr8/16/32/64 values
Value::Name(_) | Value::Here => inst::SOURCE_IMM64,
Value::Addr(v, size) => {
if let Value::Reg(_) = &**v {
match size {
IntSize::U64 => inst::SOURCE_REG_ADDR64,
IntSize::U32 => inst::SOURCE_REG_ADDR32,
IntSize::U16 => inst::SOURCE_REG_ADDR16,
IntSize::U8 => inst::SOURCE_REG_ADDR8,
}
} else {
match size {
IntSize::U64 => inst::SOURCE_ADDR64,
IntSize::U32 => inst::SOURCE_ADDR32,
IntSize::U16 => inst::SOURCE_ADDR16,
IntSize::U8 => inst::SOURCE_ADDR8,
}
}
}
}
}
}
#[derive(Debug, Clone)]
pub enum IntSize {
U8,
U16,
U32,
U64,
}
impl IntSize {
pub fn len(&self) -> usize {
match self {
IntSize::U8 => 1,
IntSize::U16 => 2,
IntSize::U32 => 4,
IntSize::U64 => 8,
}
}
}
#[derive(Debug, Clone)]
pub enum Inst {
Add(Value, Value),
Sub(Value, Value),
Mul(Value, Value),
Div(Value, Value),
IDiv(Value, Value),
Mod(Value, Value),
And(Value, Value),
Or(Value, Value),
Xor(Value, Value),
Shl(Value, Value),
Shr(Value, Value),
INeg(Value, Value),
Inv(Value, Value),
Not(Value, Value),
CmpEq(Value, Value),
CmpLt(Value, Value),
Jmp(Value),
Jz(Value),
Jnz(Value),
Call(Value),
Ret,
Push(Value),
Pop(Value),
Mov(Value, Value),
Halt,
Nop,
Dump,
}
impl Inst {
pub fn len(&self) -> usize {
match self {
Inst::Add(v1, v2)
| Inst::Sub(v1, v2)
| Inst::Mul(v1, v2)
| Inst::Div(v1, v2)
| Inst::IDiv(v1, v2)
| Inst::Mod(v1, v2)
| Inst::And(v1, v2)
| Inst::Or(v1, v2)
| Inst::Xor(v1, v2)
| Inst::Shl(v1, v2)
| Inst::Shr(v1, v2)
| Inst::INeg(v1, v2)
| Inst::Inv(v1, v2)
| Inst::Not(v1, v2)
| Inst::CmpEq(v1, v2)
| Inst::CmpLt(v1, v2)
| Inst::Mov(v1, v2) => { 3 + v1.len() + v2.len() }
Inst::Jmp(v)
| Inst::Jz(v)
| Inst::Jnz(v)
| Inst::Call(v)
| Inst::Push(v)
| Inst::Pop(v) => { 3 + v.len() }
Inst::Ret
| Inst::Halt
| Inst::Nop
| Inst::Dump => { 2 }
}
}
}

View File

@@ -0,0 +1,2 @@
struct GetLayout {
}

View File

@@ -0,0 +1,67 @@
%%
\$[0-9]+ "DEC_INT"
\$0[Xx][0-9a-fA-F]+ "HEX_INT"
\$0[Bb][01]+ "BIN_INT"
\.meta "DIR_META"
\.section "DIR_SECTION"
\.export "DIR_EXPORT"
\.include "DIR_INCLUDE"
\( "LPAREN"
\) "RPAREN"
\{ "LBRACE"
\} "RBRACE"
\[ "LBRACKET"
\] "RBRACKET"
\.\. "DOTDOT"
: "COLON"
, "COMMA"
\$\$ "BUCKBUCK"
u8 "U8"
u16 "U16"
u32 "U32"
u64 "U64"
\.u8 "U8_DEF"
\.u16 "U16_DEF"
\.u32 "U32_DEF"
\.u64 "U64_DEF"
\.[iu](8|16|32|64) "INT_DEF"
\.string "STR_DEF"
\.zstring "ZSTR_DEF"
"([^"]|\\[\\nt0"'])*" "STRING"
add "ADD"
sub "SUB"
mul "MUL"
div "DIV"
idiv "IDIV"
mod "MOD"
and "AND"
or "OR"
xor "XOR"
shl "SHL"
shr "SHR"
ineg "INEG"
inv "INV"
not "NOT"
cmpeq "CMPEQ"
cmplt "CMPLT"
jmp "JMP"
jz "JZ"
jnz "JNZ"
call "CALL"
ret "RET"
push "PUSH"
pop "POP"
mov "MOV"
halt "HALT"
nop "NOP"
dump "DUMP"
%ip "REG_IP"
%sp "REG_SP"
%fp "REG_FP"
%flags "REG_FLAGS"
%null "REG_NULL"
%status "REG_STATUS"
%r[0-9]{1,2} "REG_GENERAL"
[a-zA-Z_][a-zA-Z0-9_]* "NAME"
;[^\n]* ;
[ \n\t]+ ;

View File

@@ -0,0 +1,15 @@
pub mod ast;
pub mod parser {
use lrpar::lrpar_mod;
lrpar_mod!("obj/syn/parser.y");
pub use self::parser_y::*;
}
pub mod lexer {
use lrlex::lrlex_mod;
lrlex_mod!("obj/syn/lexer.l");
pub use self::lexer_l::*;
}

View File

@@ -0,0 +1,221 @@
%start Top
%%
Top -> Vec<Directive>:
Top Directive { $1.push($2); $1 }
| { Vec::new() }
;
Directive -> Directive:
'DIR_META' MetaBlock { Directive::Meta(MetaSection { lines: $2 }) }
| 'DIR_SECTION' Name SectionOrg DataBlock {
Directive::Data(DataSection {
name: $2,
org: $3,
lines: $4,
})
}
| 'DIR_INCLUDE' String { Directive::Include($2) }
;
MetaBlock -> Vec<MetaLine>: 'LBRACE' MetaLines 'RBRACE' { $2 };
MetaLines -> Vec<MetaLine>:
MetaLines MetaLine { $1.push($2); $1 }
| { Vec::new() }
;
MetaLine -> MetaLine: Name 'COLON' Value { MetaLine { name: $1, value: $3 } };
SectionOrg -> SectionOrg:
Int { SectionOrg::Start($1) }
| Int 'DOTDOT' Int { SectionOrg::StartEnd($1, $3) }
;
DataBlock -> Vec<DataLine>: 'LBRACE' DataLines 'RBRACE' { $2 };
DataLines -> Vec<DataLine>:
DataLines DataLine { $1.push($2); $1 }
| { Vec::new() }
;
DataLine -> DataLine:
ValueDef { DataLine::ValueDef($1) }
| Inst { DataLine::Inst($1) }
| 'DIR_EXPORT' Name { DataLine::Export($2) }
| Name 'COLON' { DataLine::Label($1) }
;
ValueDef -> ValueDef:
'U8_DEF' Int { ValueDef::Int($2, IntSize::U8) }
| 'U16_DEF' Int { ValueDef::Int($2, IntSize::U16) }
| 'U32_DEF' Int { ValueDef::Int($2, IntSize::U32) }
| 'U64_DEF' Int { ValueDef::Int($2, IntSize::U64) }
| 'STR_DEF' String { ValueDef::String($2) }
| 'ZSTR_DEF' String { ValueDef::ZString($2) }
;
Value -> Value:
Int { Value::Int($1) }
| Reg { Value::Reg($1) }
| Name { Value::Name($1) }
| 'BUCKBUCK' { Value::Here }
| 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) }
| 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) }
| 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) }
| 'LPAREN' Value 'RPAREN' 'U32' { Value::Addr(Box::new($2), IntSize::U32) }
| 'LPAREN' Value 'RPAREN' 'U64' { Value::Addr(Box::new($2), IntSize::U64) }
//| 'LBRACKET' ArrayValues 'RBRACKET' { Value::Array($2) }
;
/*
ArrayValues -> Vec<Value>:
ArrayValues Value { $1.push($2); $1 }
| { Vec::new() }
;
*/
Inst -> Inst:
'ADD' Value 'COMMA' Value { Inst::Add($2, $4) }
| 'SUB' Value 'COMMA' Value { Inst::Sub($2, $4) }
| 'MUL' Value 'COMMA' Value { Inst::Mul($2, $4) }
| 'DIV' Value 'COMMA' Value { Inst::Div($2, $4) }
| 'IDIV' Value 'COMMA' Value { Inst::IDiv($2, $4) }
| 'MOD' Value 'COMMA' Value { Inst::Mod($2, $4) }
| 'AND' Value 'COMMA' Value { Inst::And($2, $4) }
| 'OR' Value 'COMMA' Value { Inst::Or($2, $4) }
| 'XOR' Value 'COMMA' Value { Inst::Xor($2, $4) }
| 'SHL' Value 'COMMA' Value { Inst::Shl($2, $4) }
| 'SHR' Value 'COMMA' Value { Inst::Shr($2, $4) }
| 'INEG' Value 'COMMA' Value { Inst::INeg($2, $4) }
| 'INV' Value 'COMMA' Value { Inst::Inv($2, $4) }
| 'NOT' Value 'COMMA' Value { Inst::Not($2, $4) }
| 'CMPEQ' Value 'COMMA' Value { Inst::CmpEq($2, $4) }
| 'CMPLT' Value 'COMMA' Value { Inst::CmpLt($2, $4) }
| 'JMP' Value { Inst::Jmp($2) }
| 'JZ' Value { Inst::Jz($2) }
| 'JNZ' Value { Inst::Jnz($2) }
| 'CALL' Value { Inst::Call($2) }
| 'RET' { Inst::Ret }
| 'PUSH' Value { Inst::Push($2) }
| 'POP' Value { Inst::Pop($2) }
| 'MOV' Value 'COMMA' Value { Inst::Mov($2, $4) }
| 'HALT' { Inst::Halt }
| 'NOP' { Inst::Nop }
| 'DUMP' { Inst::Dump }
;
Name -> String:
'NAME' {
let v = $1.expect("could not parse name");
$lexer.span_str(v.span()).to_string()
}
;
Int -> u64:
'DEC_INT' {
let span = $1.expect("could not parse dec_int").span();
let s = &$lexer.span_str(span)[1..];
s.parse().unwrap()
}
| 'HEX_INT' {
let span = $1.expect("could not parse hex_int").span();
let s = &$lexer.span_str(span)[3..];
u64::from_str_radix(s, 16).unwrap()
}
| 'BIN_INT' {
let span = $1.expect("could not parse bin_int").span();
let s = &$lexer.span_str(span)[3..];
u64::from_str_radix(s, 2).unwrap()
}
;
Reg -> Reg:
'REG_IP' { IP }
| 'REG_SP' { SP }
| 'REG_FP' { FP }
| 'REG_FLAGS' { FLAGS }
| 'REG_NULL' { NULL }
| 'REG_STATUS' { STATUS }
| 'REG_GENERAL' {
let v = $1.expect("could not parse reg");
parse_reg($lexer.span_str(v.span())).unwrap()
}
;
String -> String:
'STRING' {
let v = $1.expect("could not parse string");
parse_string($lexer.span_str(v.span()))
}
;
%%
use crate::{
obj::syn::ast::*,
reg::*,
};
fn parse_string(input: &str) -> String {
let mut s = String::new();
let input = &input[1..input.bytes().len() - 1];
let mut chars = input.chars();
while let Some(c) = chars.next() {
if c == '\\' {
let next = chars.next().unwrap();
let c = match next {
'\\' => '\\',
'n' => '\n',
't' => '\t',
'"' => '"',
'\'' => '\'',
'0' => '\0',
_ => unreachable!(),
};
s.push(c);
} else {
s.push(c);
}
}
s
}
fn parse_reg(input: &str) -> Option<Reg> {
use regex::Regex;
use lazy_static::lazy_static;
lazy_static! {
static ref REG_RE: Regex = Regex::new(r"^%r([0-9]{1,2})$").unwrap();
}
let captures = REG_RE.captures(input)?;
let reg_no: Reg = captures.get(1)?
.as_str()
.parse()
.unwrap();
let reg = R00 + reg_no;
if reg > R31 {
None
} else {
Some(reg)
}
}
#[cfg(test)]
mod test {
use crate::reg::*;
use super::parse_reg;
#[test]
fn test_parse_reg() {
assert_eq!(parse_reg("%r00"), Some(R00));
assert_eq!(parse_reg("%r0"), Some(R00));
assert_eq!(parse_reg("%r1"), Some(R01));
assert_eq!(parse_reg("%r01"), Some(R01));
assert_eq!(parse_reg("%r31"), Some(R31));
assert_eq!(parse_reg("%r32"), None);
assert_eq!(parse_reg("%r0000"), None);
assert_eq!(parse_reg("%r9"), Some(R09));
assert_eq!(parse_reg("%r"), None);
assert_eq!(parse_reg("%r12"), Some(R12));
}
}

77
src/libvm/src/reg.rs Normal file
View File

@@ -0,0 +1,77 @@
macro_rules! registers {
{
$($variant:ident = $value:expr),* $(,)?
} => {
pub type Reg = u8;
$(
#[allow(dead_code)]
pub const $variant: Reg = $value;
)*
pub fn reg_name(reg: Reg) -> Option<&'static str> {
match reg {
$(
$value => Some(stringify!($variant)),
)*
_ => None,
}
}
};
}
registers! {
// Instruction pointer
IP = 0,
// Stack pointer
SP = 1,
// Frame pointer
FP = 2,
// Flags
FLAGS = 3,
// Zero
NULL = 4,
// General status code
STATUS = 5,
R00 = 6,
R01 = 7,
R02 = 8,
R03 = 9,
R04 = 10,
R05 = 11,
R06 = 12,
R07 = 13,
R08 = 14,
R09 = 15,
R10 = 16,
R11 = 17,
R12 = 18,
R13 = 19,
R14 = 20,
R15 = 21,
R16 = 22,
R17 = 23,
R18 = 24,
R19 = 25,
R20 = 26,
R21 = 27,
R22 = 28,
R23 = 29,
R24 = 30,
R25 = 31,
R26 = 32,
R27 = 33,
R28 = 34,
R29 = 35,
R30 = 36,
R31 = 37,
}
pub const LAST_REG: Reg = 63;
pub const NUM_REGS: usize = 64;

387
src/libvm/src/state.rs Normal file
View File

@@ -0,0 +1,387 @@
use crate::{addr::*, error::*, flags::*, inst::*, mem::*, obj::obj::*, reg::*};
pub struct State {
regs: [u64; NUM_REGS],
mem: Vec<u8>,
}
impl State {
pub fn new() -> Self {
State {
regs: [0; NUM_REGS],
mem: Default::default(),
}
}
pub fn load_object(&mut self, object: Object, max_mem: usize) -> Result<()> {
// TODO : detecting section overlap
let mem_len = object.virtual_len();
if mem_len > max_mem {
return Err(VmError::ObjectTooLarge {
object_size: mem_len,
max_mem,
});
}
let mut mem = vec![0u8; max_mem];
for section in object.sections {
match section {
Section::Data(DataSection {
name: _,
start,
len,
contents,
}) => {
for offset in 0..len {
mem[(start + offset) as usize] = contents[offset as usize];
}
}
Section::Meta(MetaSection { entries }) => {
if let Some(addr) = entries.get("entry") {
self.set_reg_unchecked(IP, *addr);
}
}
}
}
self.mem = mem;
Ok(())
}
pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> {
let mut cursor = MemCursor::new(self.mem.as_slice());
cursor.set_position(addr);
cursor
}
pub fn mem_cursor_mut(&mut self, addr: Addr) -> MemCursor<&mut [u8]> {
let mut cursor = MemCursor::new(self.mem.as_mut_slice());
cursor.set_position(addr);
cursor
}
////////////////////////////////////////////////////////////////////////////////
// Registers
////////////////////////////////////////////////////////////////////////////////
pub fn get_reg_unchecked(&self, reg: Reg) -> u64 {
self.regs[reg as usize]
}
pub fn get_reg(&self, reg: Reg) -> Result<u64> {
if (reg as usize) >= NUM_REGS {
Err(VmError::IllegalReg { reg })
} else {
Ok(self.get_reg_unchecked(reg))
}
}
pub fn set_reg_unchecked(&mut self, reg: Reg, value: u64) {
self.regs[reg as usize] = value;
}
pub fn set_reg(&mut self, reg: Reg, value: u64) -> Result<()> {
if (reg as usize) >= NUM_REGS {
Err(VmError::IllegalReg { reg })
} else {
Ok(self.set_reg_unchecked(reg, value))
}
}
////////////////////////////////////////////////////////////////////////////////
// Registers
////////////////////////////////////////////////////////////////////////////////
pub fn ip(&self) -> u64 {
self.get_reg_unchecked(IP)
}
pub fn sp(&self) -> u64 {
self.get_reg_unchecked(SP)
}
pub fn fp(&self) -> u64 {
self.get_reg_unchecked(FP)
}
////////////////////////////////////////////////////////////////////////////////
// Flags
////////////////////////////////////////////////////////////////////////////////
pub fn flags(&self) -> Flags {
// this is safe because it's OK if there are random bits flipped - this shouldn't happen
// anyway, but if it does, they're ignored
unsafe { Flags::from_bits_unchecked(self.get_reg_unchecked(FLAGS)) }
}
pub fn contains_flags(&self, flags: Flags) -> bool {
self.flags().contains(flags)
}
pub fn insert_flags(&mut self, flags: Flags) {
let mut new_flags = self.flags();
new_flags.insert(flags);
self.set_flags(new_flags);
}
pub fn remove_flags(&mut self, flags: Flags) {
let mut new_flags = self.flags();
new_flags.remove(flags);
self.set_flags(new_flags);
}
pub fn set_flags(&mut self, flags: Flags) {
self.set_reg_unchecked(FLAGS, flags.bits());
}
////////////////////////////////////////////////////////////////////////////////
// Execution
////////////////////////////////////////////////////////////////////////////////
pub fn is_halted(&self) -> bool {
self.contains_flags(Flags::HALT)
}
pub fn exec(&mut self) -> Result<u64> {
while !self.is_halted() {
self.tick()?;
}
Ok(self.get_reg_unchecked(STATUS))
}
fn tick(&mut self) -> Result<()> {
let mut cursor = self.mem_cursor(Addr(self.ip()));
let inst = cursor.next_inst()?;
let mut next_ip = self.ip() + (inst.len() as u64);
match inst {
Inst::Add(d, s) => {
let value = self.load_dest(d)?.wrapping_add(self.load_source(s)?);
self.store_dest(d, value)?;
}
Inst::Sub(d, s) => {
let value = self.load_dest(d)?.wrapping_sub(self.load_source(s)?);
self.store_dest(d, value)?;
}
Inst::Mul(d, s) => {
let value = self.load_dest(d)?.wrapping_mul(self.load_source(s)?);
self.store_dest(d, value)?;
}
Inst::Div(d, s) => {
// TODO : catch divide by zero
let value = self.load_dest(d)?.wrapping_div(self.load_source(s)?);
self.store_dest(d, value)?;
}
Inst::IDiv(d, s) => {
// TODO : catch divide by zero
let dest = self.load_dest(d)? as i64;
let source = self.load_source(s)? as i64;
let value = dest.wrapping_div(source);
self.store_dest(d, value as u64)?;
}
Inst::Mod(d, s) => {
let value = self.load_dest(d)? % self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::And(d, s) => {
let value = self.load_dest(d)? & self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Or(d, s) => {
let value = self.load_dest(d)? | self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Xor(d, s) => {
let value = self.load_dest(d)? ^ self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Shl(d, s) => {
let value = self.load_dest(d)? << self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Shr(d, s) => {
let value = self.load_dest(d)? >> self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::INeg(d, s) => {
let value = (!self.load_source(s)?).wrapping_add(1);
self.store_dest(d, value)?;
}
Inst::Inv(d, s) => {
let value = !self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Not(d, s) => {
let value = (self.load_source(s)? == 0) as u64;
self.store_dest(d, value)?;
}
Inst::CmpEq(s1, s2) => {
let cmp = self.load_source(s1)? == self.load_source(s2)?;
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
}
Inst::CmpLt(s1, s2) => {
let cmp = self.load_source(s1)? < self.load_source(s2)?;
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
}
Inst::Jmp(s) => {
next_ip = self.load_source(s)?;
}
Inst::Jz(s) => {
if !self.contains_flags(Flags::COMPARE) {
next_ip = self.load_source(s)?;
}
}
Inst::Jnz(s) => {
if self.contains_flags(Flags::COMPARE) {
next_ip = self.load_source(s)?;
}
}
Inst::Call(s) => {
{
let fp = self.fp();
let ip = next_ip;
self.push(Source::Imm(fp))?;
self.push(Source::Imm(ip))?;
}
{
let sp = self.sp();
self.set_reg_unchecked(FP, sp - 16);
next_ip = self.load_source(s)?;
}
}
Inst::Ret => {
let fp = self.fp();
let sp = fp + 16;
self.set_reg_unchecked(SP, sp);
self.pop(Dest::Reg(IP))?;
self.pop(Dest::Reg(FP))?;
next_ip = self.ip();
}
Inst::Push(s) => {
self.push(s)?;
}
Inst::Pop(d) => {
self.pop(d)?;
}
Inst::Mov(d, s) => {
let value = self.load_source(s)?;
self.store_dest(d, value)?;
}
Inst::Halt => {
self.insert_flags(Flags::HALT);
}
Inst::Nop => {}
Inst::Dump => {
// TODO - dump
}
}
self.set_reg_unchecked(IP, next_ip);
Ok(())
}
fn push(&mut self, source: Source) -> Result<()> {
let value = self.load_source(source)?;
let mut stack_addr = self.sp();
// create a destination based on the size of the source
let dest = match source {
Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => Dest::Addr64(Addr(stack_addr)),
Source::Addr32(_) | Source::RegAddr32(_) => Dest::Addr32(Addr(stack_addr)),
Source::Addr16(_) | Source::RegAddr16(_) => Dest::Addr16(Addr(stack_addr)),
Source::Addr8(_) | Source::RegAddr8(_) => Dest::Addr8(Addr(stack_addr)),
};
self.store_dest(dest, value)?;
assert_eq!(source.value_len(), dest.value_len());
stack_addr += source.value_len() as u64;
self.set_reg_unchecked(SP, stack_addr);
Ok(())
}
fn pop(&mut self, dest: Dest) -> Result<()> {
let sp = self.sp() - (dest.value_len() as u64);
let sp_source = match dest {
Dest::Addr64(_) | Dest::RegAddr64(_) | Dest::Reg(_) => Source::Addr64(Addr(sp)),
Dest::Addr32(_) | Dest::RegAddr32(_) => Source::Addr32(Addr(sp)),
Dest::Addr16(_) | Dest::RegAddr16(_) => Source::Addr16(Addr(sp)),
Dest::Addr8(_) | Dest::RegAddr8(_) => Source::Addr8(Addr(sp)),
};
let value = self.load_source(sp_source)?;
// Set the SP first, because the destination may be the SP itself
self.set_reg_unchecked(SP, sp);
self.store_dest(dest, value)?;
Ok(())
}
fn store_dest(&mut self, dest: Dest, value: u64) -> Result<()> {
match dest {
Dest::Addr64(a) => self.mem_cursor_mut(a).write_u64(value),
Dest::Addr32(a) => self
.mem_cursor_mut(a)
.write_u32((value & 0xffff_ffff) as u32),
Dest::Addr16(a) => self.mem_cursor_mut(a).write_u16((value & 0xffff) as u16),
Dest::Addr8(a) => self.mem_cursor_mut(a).write_u8((value & 0xff) as u8),
Dest::RegAddr64(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u64(value)
}
Dest::RegAddr32(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr)
.write_u32((value & 0xffff_ffff) as u32)
}
Dest::RegAddr16(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u16((value & 0xffff) as u16)
}
Dest::RegAddr8(r) => {
let addr = Addr(self.get_reg(r)?);
self.mem_cursor_mut(addr).write_u8((value & 0xff) as u8)
}
Dest::Reg(reg) => self.set_reg(reg, value),
}
}
fn load_source(&self, source: Source) -> Result<u64> {
let value = match source {
Source::Addr64(a) => self.mem_cursor(a).next_u64()?,
Source::Addr32(a) => self.mem_cursor(a).next_u32()? as u64,
Source::Addr16(a) => self.mem_cursor(a).next_u16()? as u64,
Source::Addr8(a) => self.mem_cursor(a).next_u8()? as u64,
Source::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?,
Source::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64,
Source::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64,
Source::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64,
Source::Reg(reg) => self.get_reg(reg)?,
Source::Imm(u) => u,
};
Ok(value)
}
fn load_dest(&self, dest: Dest) -> Result<u64> {
let value = match dest {
Dest::Addr64(a) => self.mem_cursor(a).next_u64()?,
Dest::Addr32(a) => self.mem_cursor(a).next_u32()? as u64,
Dest::Addr16(a) => self.mem_cursor(a).next_u16()? as u64,
Dest::Addr8(a) => self.mem_cursor(a).next_u8()? as u64,
Dest::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?,
Dest::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64,
Dest::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64,
Dest::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64,
Dest::Reg(reg) => self.get_reg(reg)?,
};
Ok(value)
}
}

189
src/libvm/src/tick.rs Normal file
View File

@@ -0,0 +1,189 @@
use crate::{error::*, flags::Flags, inst::*, reg::*, vm::*, visit::*, mem::MemCursor};
impl Vm {
pub fn tick(&mut self) -> Result<()> {
let next_ip = self.visit_inst()?;
self.set_reg(IP, next_ip);
Ok(())
}
fn next_ip(&self) -> Result<Addr> {
let ip = self.ip();
let op = self.get_inst_op(ip)?;
Ok(ip + (inst_len(op) as u64))
}
fn with_regs<F, B>(&mut self, r1: Reg, r2: Reg, mapping: F) -> B
where F: FnOnce(Word, Word) -> B
{
let w1 = self.get_reg(r1);
let w2 = self.get_reg(r2);
(mapping)(w1, w2)
}
}
impl VisitInst for Vm {
type Out = Addr;
fn cursor(&self) -> MemCursor {
self.mem_cursor(self.ip() as usize)
}
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_add(w2));
self.set_reg(r1, out);
self.next_ip()
}
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_mul(w2));
self.set_reg(r1, out);
self.next_ip()
}
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
// TODO : check w2 == 0 and throw error/exception
let out = self.with_regs(r1, r2, |w1, w2| w1 / w2);
self.set_reg(r1, out);
self.next_ip()
}
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
// TODO : check w2 == 0 and throw error/exception
let out = self.with_regs(r1, r2, |w1, w2| w1 % w2);
self.set_reg(r1, out);
self.next_ip()
}
fn ineg(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, (!w1).wrapping_add(1));
self.next_ip()
}
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 & w2);
self.set_reg(r1, out);
self.next_ip()
}
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 | w2);
self.set_reg(r1, out);
self.next_ip()
}
fn inv(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, !w1);
self.next_ip()
}
fn not(&mut self, r1: Reg) -> Result<Self::Out> {
let w1 = self.get_reg(r1);
self.set_reg(r1, (w1 == 0) as Word);
self.next_ip()
}
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 ^ w2);
self.set_reg(r1, out);
self.next_ip()
}
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 << w2);
self.set_reg(r1, out);
self.next_ip()
}
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let out = self.with_regs(r1, r2, |w1, w2| w1 >> w2);
self.set_reg(r1, out);
self.next_ip()
}
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let cmp = self.with_regs(r1, r2, |w1, w2| w1 == w2);
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
self.next_ip()
}
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let cmp = self.with_regs(r1, r2, |w1, w2| w1 < w2);
if cmp {
self.insert_flags(Flags::COMPARE);
} else {
self.remove_flags(Flags::COMPARE);
}
self.next_ip()
}
fn jmp(&mut self, r1: Reg) -> Result<Self::Out> {
let addr = self.get_reg(r1);
Ok(addr)
}
fn jz(&mut self, r1: Reg) -> Result<Self::Out> {
if !self.flags().contains(Flags::COMPARE) {
Ok(self.get_reg(r1))
} else {
self.next_ip()
}
}
fn jnz(&mut self, r1: Reg) -> Result<Self::Out> {
if self.flags().contains(Flags::COMPARE) {
Ok(self.get_reg(r1))
} else {
self.next_ip()
}
}
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = Vm::load(self, r2)?;
self.set_reg_checked(r1, value)?;
self.next_ip()
}
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = self.get_reg_checked(r2)?;
self.set_reg_checked(r1, value)?;
self.next_ip()
}
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out> {
self.set_reg_checked(r1, w1)?;
self.next_ip()
}
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out> {
self.set_reg_checked(r1, w1 as Word)?;
self.next_ip()
}
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = Vm::load(self, r2)?;
self.store(r1, value)?;
self.next_ip()
}
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
let value = self.get_reg_checked(r1)?;
self.store(r2, value)?;
self.next_ip()
}
fn halt(&mut self) -> Result<Self::Out> {
self.insert_flags(Flags::HALT);
self.next_ip()
}
fn nop(&mut self) -> Result<Self::Out> {
self.next_ip()
}
}