Initialize the repository
This commit is contained in:
commit
601dd33c88
|
@ -0,0 +1,33 @@
|
|||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
- name: Build ruxnasm
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
- name: Test ruxnasm
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
*.swp
|
||||
*.bin
|
||||
.DS_Store
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"rust-analyzer.cargo.allFeatures": true,
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruxnasm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"codespan-reporting",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "ruxnasm"
|
||||
version = "0.1.0"
|
||||
authors = ["Karol Belina <karolbelina@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[[bin]]
|
||||
name = "ruxnasm"
|
||||
required-features = ["codespan-reporting"]
|
||||
|
||||
[dependencies]
|
||||
codespan-reporting = { version = "0.11.1", optional = true }
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Karol Belina
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1 @@
|
|||
nightly-2021-05-17
|
|
@ -0,0 +1,118 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum InstructionKind {
|
||||
Break,
|
||||
Literal,
|
||||
NoOperation,
|
||||
Pop,
|
||||
Duplicate,
|
||||
Swap,
|
||||
Over,
|
||||
Rotate,
|
||||
Equal,
|
||||
NotEqual,
|
||||
GreaterThan,
|
||||
LesserThan,
|
||||
Jump,
|
||||
JumpCondition,
|
||||
JumpStash,
|
||||
Stash,
|
||||
LoadZeroPage,
|
||||
StoreZeroPage,
|
||||
LoadRelative,
|
||||
StoreRelative,
|
||||
LoadAbsolute,
|
||||
StoreAbsolute,
|
||||
DeviceIn,
|
||||
DeviceOut,
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
And,
|
||||
Or,
|
||||
ExclusiveOr,
|
||||
Shift,
|
||||
}
|
||||
|
||||
impl From<InstructionKind> for u8 {
|
||||
fn from(instruction_kind: InstructionKind) -> Self {
|
||||
match instruction_kind {
|
||||
InstructionKind::Break => 0x00,
|
||||
InstructionKind::Literal => 0x01,
|
||||
InstructionKind::NoOperation => 0x02,
|
||||
InstructionKind::Pop => 0x03,
|
||||
InstructionKind::Duplicate => 0x04,
|
||||
InstructionKind::Swap => 0x05,
|
||||
InstructionKind::Over => 0x06,
|
||||
InstructionKind::Rotate => 0x07,
|
||||
InstructionKind::Equal => 0x08,
|
||||
InstructionKind::NotEqual => 0x09,
|
||||
InstructionKind::GreaterThan => 0x0a,
|
||||
InstructionKind::LesserThan => 0x0b,
|
||||
InstructionKind::Jump => 0x0c,
|
||||
InstructionKind::JumpCondition => 0x0d,
|
||||
InstructionKind::JumpStash => 0x0e,
|
||||
InstructionKind::Stash => 0x0f,
|
||||
InstructionKind::LoadZeroPage => 0x10,
|
||||
InstructionKind::StoreZeroPage => 0x11,
|
||||
InstructionKind::LoadRelative => 0x12,
|
||||
InstructionKind::StoreRelative => 0x13,
|
||||
InstructionKind::LoadAbsolute => 0x14,
|
||||
InstructionKind::StoreAbsolute => 0x15,
|
||||
InstructionKind::DeviceIn => 0x16,
|
||||
InstructionKind::DeviceOut => 0x17,
|
||||
InstructionKind::Add => 0x18,
|
||||
InstructionKind::Subtract => 0x19,
|
||||
InstructionKind::Multiply => 0x1a,
|
||||
InstructionKind::Divide => 0x1b,
|
||||
InstructionKind::And => 0x1c,
|
||||
InstructionKind::Or => 0x1d,
|
||||
InstructionKind::ExclusiveOr => 0x1e,
|
||||
InstructionKind::Shift => 0x1f,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for InstructionKind {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"BRK" => Ok(InstructionKind::Break),
|
||||
"LIT" => Ok(InstructionKind::Literal),
|
||||
"NOP" => Ok(InstructionKind::NoOperation),
|
||||
"POP" => Ok(InstructionKind::Pop),
|
||||
"DUP" => Ok(InstructionKind::Duplicate),
|
||||
"SWP" => Ok(InstructionKind::Swap),
|
||||
"OVR" => Ok(InstructionKind::Over),
|
||||
"ROT" => Ok(InstructionKind::Rotate),
|
||||
"EQU" => Ok(InstructionKind::Equal),
|
||||
"NEQ" => Ok(InstructionKind::NotEqual),
|
||||
"GTH" => Ok(InstructionKind::GreaterThan),
|
||||
"LTH" => Ok(InstructionKind::LesserThan),
|
||||
"JMP" => Ok(InstructionKind::Jump),
|
||||
"JCN" => Ok(InstructionKind::JumpCondition),
|
||||
"JSR" => Ok(InstructionKind::JumpStash),
|
||||
"STH" => Ok(InstructionKind::Stash),
|
||||
"LDZ" => Ok(InstructionKind::LoadZeroPage),
|
||||
"STZ" => Ok(InstructionKind::StoreZeroPage),
|
||||
"LDR" => Ok(InstructionKind::LoadRelative),
|
||||
"STR" => Ok(InstructionKind::StoreRelative),
|
||||
"LDA" => Ok(InstructionKind::LoadAbsolute),
|
||||
"STA" => Ok(InstructionKind::StoreAbsolute),
|
||||
"DEI" => Ok(InstructionKind::DeviceIn),
|
||||
"DEO" => Ok(InstructionKind::DeviceOut),
|
||||
"ADD" => Ok(InstructionKind::Add),
|
||||
"SUB" => Ok(InstructionKind::Subtract),
|
||||
"MUL" => Ok(InstructionKind::Multiply),
|
||||
"DIV" => Ok(InstructionKind::Divide),
|
||||
"AND" => Ok(InstructionKind::And),
|
||||
"ORA" => Ok(InstructionKind::Or),
|
||||
"EOR" => Ok(InstructionKind::ExclusiveOr),
|
||||
"SFT" => Ok(InstructionKind::Shift),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
pub mod instruction;
|
||||
pub mod span;
|
||||
|
||||
pub use instruction::*;
|
||||
pub use span::*;
|
||||
|
||||
pub fn assemble(_source_contents: &str) -> Result<Vec<u8>, ()> {
|
||||
todo!()
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
pub mod reader;
|
||||
pub mod reporter;
|
||||
pub mod writer;
|
||||
|
||||
fn main() {
|
||||
todo!()
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CouldNotReadFile {
|
||||
file_path: PathBuf,
|
||||
io_error: io::Error,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
pub use error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
mod error;
|
||||
|
||||
pub fn read(path: &Path) -> Result<String, Error> {
|
||||
fs::read_to_string(path).map_err(|io_error| Error::CouldNotReadFile {
|
||||
file_path: path.to_path_buf(),
|
||||
io_error,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
use ruxnasm::Span;
|
||||
|
||||
pub struct VoidDiagnosticBuilderStage1;
|
||||
|
||||
impl VoidDiagnosticBuilderStage1 {
|
||||
pub fn with_message(self, message: impl Into<String>) -> VoidDiagnostic {
|
||||
VoidDiagnostic {
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VoidDiagnostic {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl<'a> VoidDiagnostic {
|
||||
pub fn error() -> VoidDiagnosticBuilderStage1 {
|
||||
VoidDiagnosticBuilderStage1
|
||||
}
|
||||
|
||||
pub fn message(&'a self) -> &'a str {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileDiagnosticBuilderStage1;
|
||||
|
||||
impl FileDiagnosticBuilderStage1 {
|
||||
pub fn with_message(self, message: impl Into<String>) -> FileDiagnosticBuilderStage2 {
|
||||
FileDiagnosticBuilderStage2 {
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileDiagnosticBuilderStage2 {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl FileDiagnosticBuilderStage2 {
|
||||
pub fn with_label(self, label: Label) -> FileDiagnostic {
|
||||
FileDiagnostic {
|
||||
message: self.message,
|
||||
label,
|
||||
additional_labels: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileDiagnostic {
|
||||
message: String,
|
||||
label: Label,
|
||||
additional_labels: Vec<Label>,
|
||||
}
|
||||
|
||||
impl<'a> FileDiagnostic {
|
||||
pub fn error() -> FileDiagnosticBuilderStage1 {
|
||||
FileDiagnosticBuilderStage1
|
||||
}
|
||||
|
||||
pub fn with_label(mut self, label: Label) -> FileDiagnostic {
|
||||
self.additional_labels.push(label);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn message(&'a self) -> &'a str {
|
||||
&self.message
|
||||
}
|
||||
|
||||
pub fn labels(&self) -> Labels {
|
||||
Labels {
|
||||
label: self.label.clone(),
|
||||
additional_labels: self.additional_labels.clone(),
|
||||
counter: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Label {
|
||||
pub style: LabelStyle,
|
||||
pub span: Span,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum LabelStyle {
|
||||
Primary,
|
||||
Secondary,
|
||||
}
|
||||
|
||||
pub struct Labels {
|
||||
label: Label,
|
||||
additional_labels: Vec<Label>,
|
||||
counter: usize,
|
||||
}
|
||||
|
||||
impl Iterator for Labels {
|
||||
type Item = Label;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let result = if self.counter == 0 {
|
||||
Some(self.label.clone())
|
||||
} else {
|
||||
self.additional_labels.get(self.counter - 1).cloned()
|
||||
};
|
||||
self.counter += 1;
|
||||
result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
use codespan_reporting::files;
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct File<'a> {
|
||||
/// The name of the file.
|
||||
name: String,
|
||||
/// The source code of the file.
|
||||
source: &'a str,
|
||||
/// The starting byte indices in the source code.
|
||||
line_starts: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<'a> File<'a> {
|
||||
pub fn new(name: &'a Path, source: &'a str) -> Self {
|
||||
let name = name.to_string_lossy().into_owned();
|
||||
let line_starts = files::line_starts(&source).collect();
|
||||
|
||||
Self {
|
||||
name,
|
||||
source,
|
||||
line_starts,
|
||||
}
|
||||
}
|
||||
|
||||
fn line_start(&self, line_index: usize) -> Result<usize, files::Error> {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
match line_index.cmp(&self.line_starts.len()) {
|
||||
Ordering::Less => Ok(self
|
||||
.line_starts
|
||||
.get(line_index)
|
||||
.expect("failed despite previous check")
|
||||
.clone()),
|
||||
Ordering::Equal => Ok(self.source.len()),
|
||||
Ordering::Greater => Err(files::Error::LineTooLarge {
|
||||
given: line_index,
|
||||
max: self.line_starts.len() - 1,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> files::Files<'a> for File<'a> {
|
||||
type FileId = ();
|
||||
type Name = &'a str;
|
||||
type Source = &'a str;
|
||||
|
||||
fn name(&self, _file_id: ()) -> Result<&str, files::Error> {
|
||||
Ok(&self.name)
|
||||
}
|
||||
|
||||
fn source(&self, _file_id: ()) -> Result<&str, files::Error> {
|
||||
Ok(&self.source)
|
||||
}
|
||||
|
||||
fn line_index(&self, _file_id: (), byte_index: usize) -> Result<usize, files::Error> {
|
||||
self.line_starts
|
||||
.binary_search(&byte_index)
|
||||
.or_else(|next_line| Ok(next_line - 1))
|
||||
}
|
||||
|
||||
fn line_range(&self, _file_id: (), line_index: usize) -> Result<Range<usize>, files::Error> {
|
||||
let line_start = self.line_start(line_index)?;
|
||||
let next_line_start = self.line_start(line_index + 1)?;
|
||||
|
||||
Ok(line_start..next_line_start)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Void;
|
||||
|
||||
impl<'a> files::Files<'a> for Void {
|
||||
type FileId = ();
|
||||
type Name = &'a str;
|
||||
type Source = &'a str;
|
||||
|
||||
fn name(&self, _file_id: ()) -> Result<&str, files::Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn source(&self, _file_id: ()) -> Result<&str, files::Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn line_index(&self, _file_id: (), _byte_index: usize) -> Result<usize, files::Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn line_range(&self, _file_id: (), _line_index: usize) -> Result<Range<usize>, files::Error> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
use diagnostic::{FileDiagnostic, Label, LabelStyle, VoidDiagnostic};
|
||||
use file::{File, Void};
|
||||
use std::path::Path;
|
||||
|
||||
mod diagnostic;
|
||||
mod file;
|
||||
|
||||
pub struct VoidReporter {
|
||||
pub writer: codespan_reporting::term::termcolor::StandardStream,
|
||||
pub config: codespan_reporting::term::Config,
|
||||
}
|
||||
|
||||
impl VoidReporter {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
writer: codespan_reporting::term::termcolor::StandardStream::stderr(
|
||||
codespan_reporting::term::termcolor::ColorChoice::Always,
|
||||
),
|
||||
config: codespan_reporting::term::Config {
|
||||
display_style: codespan_reporting::term::DisplayStyle::Rich,
|
||||
tab_width: 2,
|
||||
#[cfg(windows)]
|
||||
styles: with_blue(codespan_reporting::term::termcolor::Color::Cyan),
|
||||
#[cfg(not(windows))]
|
||||
styles: with_blue(codespan_reporting::term::termcolor::Color::Blue),
|
||||
chars: codespan_reporting::term::Chars::default(),
|
||||
start_context_lines: 3,
|
||||
end_context_lines: 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn promote<'a>(self, file_path: &'a Path, file_contents: &'a str) -> FileReporter<'a> {
|
||||
FileReporter {
|
||||
file: File::new(file_path, file_contents),
|
||||
writer: self.writer,
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, diagnostic: VoidDiagnostic) {
|
||||
let codespan_diagnostic =
|
||||
codespan_reporting::diagnostic::Diagnostic::error().with_message(diagnostic.message());
|
||||
let _ = codespan_reporting::term::emit(
|
||||
&mut self.writer.lock(),
|
||||
&self.config,
|
||||
&Void,
|
||||
&codespan_diagnostic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileReporter<'a> {
|
||||
pub file: File<'a>,
|
||||
pub writer: codespan_reporting::term::termcolor::StandardStream,
|
||||
pub config: codespan_reporting::term::Config,
|
||||
}
|
||||
|
||||
impl<'a> FileReporter<'a> {
|
||||
pub fn demote(self) -> VoidReporter {
|
||||
VoidReporter {
|
||||
writer: self.writer,
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, diagnostic: FileDiagnostic) {
|
||||
let codespan_diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
|
||||
.with_message(diagnostic.message())
|
||||
.with_labels(
|
||||
diagnostic
|
||||
.labels()
|
||||
.map(
|
||||
|label: Label| -> codespan_reporting::diagnostic::Label<()> {
|
||||
match label.style {
|
||||
LabelStyle::Primary => {
|
||||
codespan_reporting::diagnostic::Label::primary(
|
||||
(),
|
||||
label.span.from.offset..label.span.to.offset,
|
||||
)
|
||||
.with_message(&label.message)
|
||||
}
|
||||
LabelStyle::Secondary => {
|
||||
codespan_reporting::diagnostic::Label::secondary(
|
||||
(),
|
||||
label.span.from.offset..label.span.to.offset,
|
||||
)
|
||||
.with_message(&label.message)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
);
|
||||
let _ = codespan_reporting::term::emit(
|
||||
&mut self.writer.lock(),
|
||||
&self.config,
|
||||
&self.file,
|
||||
&codespan_diagnostic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn with_blue(blue: codespan_reporting::term::termcolor::Color) -> codespan_reporting::term::Styles {
|
||||
use codespan_reporting::term::{
|
||||
termcolor::{Color, ColorSpec},
|
||||
Styles,
|
||||
};
|
||||
|
||||
let mut header = ColorSpec::new().set_bold(true).set_intense(true).clone();
|
||||
|
||||
Styles {
|
||||
header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
|
||||
header_error: header.clone().set_fg(Some(Color::Red)).clone(),
|
||||
header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
|
||||
header_note: header.clone().set_fg(Some(Color::Green)).clone(),
|
||||
header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
|
||||
header_message: header.clone(),
|
||||
|
||||
primary_label_bug: header.clone().set_fg(Some(Color::Red)).clone(),
|
||||
primary_label_error: header.clone().set_fg(Some(Color::Red)).clone(),
|
||||
primary_label_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
|
||||
primary_label_note: header.clone().set_fg(Some(Color::Green)).clone(),
|
||||
primary_label_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
|
||||
secondary_label: header.clone().set_fg(Some(blue)).clone(),
|
||||
|
||||
line_number: header.clone().set_fg(Some(blue)).clone(),
|
||||
source_border: header.clone().set_fg(Some(blue)).clone(),
|
||||
note_bullet: header.set_fg(Some(blue)).clone(),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Location {
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Span {
|
||||
pub from: Location,
|
||||
pub to: Location,
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub fn combine(start: &Span, end: &Span) -> Span {
|
||||
Span {
|
||||
from: start.from,
|
||||
to: end.to,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct Spanned<T> {
|
||||
pub node: T,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for Spanned<T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::error::Error for Spanned<T> where T: std::error::Error {}
|
||||
|
||||
pub trait Spanning
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn spanning(self, span: Span) -> Spanned<Self>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_spanning {
|
||||
($impl_type:ty) => {
|
||||
impl<'a> Spanning for $impl_type {
|
||||
fn spanning(self, span: Span) -> Spanned<$impl_type> {
|
||||
Spanned { node: self, span }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_spanning!(String);
|
||||
impl_spanning!(u64);
|
||||
impl_spanning!(usize);
|
||||
impl_spanning!(&'a str);
|
||||
impl_spanning!(Vec<u8>);
|
|
@ -0,0 +1,10 @@
|
|||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CouldNotWriteFile {
|
||||
file_path: PathBuf,
|
||||
io_error: io::Error,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
pub use error::Error;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
mod error;
|
||||
|
||||
pub fn write(path: &Path, binary: &[u8]) -> Result<(), Error> {
|
||||
let mut file = fs::File::create(path).map_err(|io_error| Error::CouldNotWriteFile {
|
||||
file_path: path.to_path_buf(),
|
||||
io_error,
|
||||
})?;
|
||||
file.write_all(binary)
|
||||
.map_err(|io_error| Error::CouldNotWriteFile {
|
||||
file_path: path.to_path_buf(),
|
||||
io_error,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue