Skip to content

Provide library access to code generation #214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 76 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,82 @@
//!
//! - `#[feature(untagged_unions)]` for overlapping/overloaded registers

// NOTE This file is for documentation only
#![recursion_limit = "128"]

extern crate cast;
extern crate either;
#[macro_use]
extern crate error_chain;
extern crate inflections;
#[macro_use]
extern crate quote;
extern crate svd_parser as svd;
extern crate syn;

mod errors;
mod generate;
mod util;

pub use util::Target;

pub struct Generation {
pub lib_rs: String,
pub device_specific: Option<DeviceSpecific>,

// Reserve the right to add more fields to this struct
_extensible: (),
}

pub struct DeviceSpecific {
pub device_x: String,
pub build_rs: String,

// Reserve the right to add more fields to this struct
_extensible: (),
}

type Result<T> = std::result::Result<T, SvdError>;
#[derive(Debug)]
pub enum SvdError {
Fmt,
Render,
}

/// Generates rust code for the specified svd content.
pub fn generate(xml: &str, target: &Target, nightly: bool) -> Result<Generation> {
use std::fmt::Write;

let device = svd::parse(xml);
let mut device_x = String::new();
let items = generate::device::render(&device, target, nightly, &mut device_x)
.or(Err(SvdError::Render))?;

let mut lib_rs = String::new();
writeln!(
&mut lib_rs,
"{}",
quote! {
#(#items)*
}
)
.or(Err(SvdError::Fmt))?;

let device_specific = if device_x.is_empty() {
None
} else {
Some(DeviceSpecific {
device_x: device_x,
build_rs: util::build_rs().to_string(),
_extensible: (),
})
};

Ok(Generation {
lib_rs: lib_rs,
device_specific: device_specific,
_extensible: (),
})
}

/// Assigns a handler to an interrupt
///
Expand Down
47 changes: 1 addition & 46 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,10 @@ use std::fs::File;
use std::process;
use std::io::{self, Write};

use quote::Tokens;
use clap::{App, Arg};

use errors::*;

#[derive(Clone, Copy, PartialEq)]
pub enum Target {
CortexM,
Msp430,
RISCV,
None,
}

impl Target {
fn parse(s: &str) -> Result<Self> {
Ok(match s {
"cortex-m" => Target::CortexM,
"msp430" => Target::Msp430,
"riscv" => Target::RISCV,
"none" => Target::None,
_ => bail!("unknown target {}", s),
})
}
}
use util::{build_rs, Target};

fn run() -> Result<()> {
use std::io::Read;
Expand Down Expand Up @@ -135,28 +115,3 @@ fn main() {
process::exit(1);
}
}

fn build_rs() -> Tokens {
quote! {
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
if env::var_os("CARGO_FEATURE_RT").is_some() {
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("device.x"))
.unwrap()
.write_all(include_bytes!("device.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

println!("cargo:rerun-if-changed=device.x");
}

println!("cargo:rerun-if-changed=build.rs");
}
}
}
45 changes: 45 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ pub const BITS_PER_BYTE: u32 = 8;
/// that are not valid in Rust ident
const BLACKLIST_CHARS : &[char] = &['(', ')', '[', ']', '/', ' '];

#[derive(Clone, Copy, PartialEq)]
pub enum Target {
CortexM,
Msp430,
RISCV,
None,
}

impl Target {
pub fn parse(s: &str) -> Result<Self> {
Ok(match s {
"cortex-m" => Target::CortexM,
"msp430" => Target::Msp430,
"riscv" => Target::RISCV,
"none" => Target::None,
_ => bail!("unknown target {}", s),
})
}
}

pub trait ToSanitizedPascalCase {
fn to_sanitized_pascal_case(&self) -> Cow<str>;
}
Expand Down Expand Up @@ -291,3 +311,28 @@ pub fn only_registers(ercs: &[Either<Register, Cluster>]) -> Vec<&Register> {
.collect();
registers
}

pub fn build_rs() -> Tokens {
quote! {
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
if env::var_os("CARGO_FEATURE_RT").is_some() {
// Put the linker script somewhere the linker can find it
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("device.x"))
.unwrap()
.write_all(include_bytes!("device.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

println!("cargo:rerun-if-changed=device.x");
}

println!("cargo:rerun-if-changed=build.rs");
}
}
}