Skip to content
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
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- `canadensis_dsdl_parser`: Breaking change: Added Config, with options for `byte`, `utf8`, and `saturated bool`
- `canadensis_dsdl_parser`: Added support for `byte` and `utf8` types (this is a breaking change for code that uses
this library, but it does not break compatibility with any existing DSDL file)
- `canadensis_dsdl_frontend`: Breaking change: Added Config, with options for `byte`, `utf8`, and `saturated bool`
- `canadensis_macro`: Added options for `byte`, `utf8`, and `saturated bool` (not a breaking change)
- `canadensis_codegen_rust`: Added unstable optional support for `byte` and `utf8` (code generation is the same as for uint8)
- `canadensis_codegen_rust`: Added unstable option to forbid `saturated bool`

## [canadensis-v0.3.3](https://github.com/samcrow/canadensis/releases/tag/canadensis-v0.3.3) - 2025-03-23

### Fixed
Expand Down Expand Up @@ -538,4 +546,4 @@ This section is not complete because version 0.2.0 had too many changes.

## [0.1.0](https://github.com/samcrow/canadensis/tree/v0.1.0) - 2021-07-11

Initial release
Initial release
3 changes: 3 additions & 0 deletions canadensis_codegen_rust/src/impl_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ impl Display for ImplementConstants<'_, '_> {
let name = make_rust_identifier(name.clone());
let rust_type_name: String = match constant.ty() {
PrimitiveType::Boolean => "bool".into(),
PrimitiveType::Byte | PrimitiveType::Utf8 => {
panic!("Constant type can't be byte or utf8")
}
PrimitiveType::Int { bits } => format!("i{}", round_up_integer_size(*bits)),
PrimitiveType::UInt { bits, .. } => format!("u{}", round_up_integer_size(*bits)),
PrimitiveType::Float16 { .. } => "::half::f16".into(),
Expand Down
22 changes: 4 additions & 18 deletions canadensis_codegen_rust/src/impl_deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,7 @@ struct ReadUnalignedField<'t> {
impl Display for ReadUnalignedField<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match &self.ty {
ResolvedType::Scalar(scalar) => match scalar {
ResolvedScalarType::Composite { .. } => {
write!(f, "cursor.read_composite()?")?;
}
ResolvedScalarType::Primitive(primitive) => match primitive {
PrimitiveType::Boolean => write!(f, "cursor.read_bool()")?,
PrimitiveType::Int { bits } => {
Display::fmt(&CallRead { bits: *bits }, f)?;
}
PrimitiveType::UInt { bits, .. } => {
Display::fmt(&CallRead { bits: *bits }, f)?;
}
PrimitiveType::Float16 { .. } => writeln!(f, "cursor.read_f16()")?,
PrimitiveType::Float32 { .. } => writeln!(f, "cursor.read_f32()")?,
PrimitiveType::Float64 { .. } => writeln!(f, "cursor.read_f64()")?,
},
ResolvedScalarType::Void { bits } => writeln!(f, "cursor.skip_{}();", *bits)?,
},
ResolvedType::Scalar(scalar) => Display::fmt(&ReadUnalignedScalar { ty: scalar }, f)?,
ResolvedType::FixedArray {
inner: ResolvedScalarType::Primitive(PrimitiveType::Boolean),
len,
Expand Down Expand Up @@ -230,6 +213,9 @@ impl Display for ReadUnalignedScalar<'_> {
}
ResolvedScalarType::Primitive(primitive) => match primitive {
PrimitiveType::Boolean => write!(f, "cursor.read_bool()")?,
PrimitiveType::Utf8 | PrimitiveType::Byte => {
Display::fmt(&CallRead { bits: 8 }, f)?
}
PrimitiveType::Int { bits } => Display::fmt(&CallRead { bits: *bits }, f)?,
PrimitiveType::UInt { bits, .. } => Display::fmt(&CallRead { bits: *bits }, f)?,
PrimitiveType::Float16 { .. } => write!(f, "cursor.read_f16()")?,
Expand Down
24 changes: 23 additions & 1 deletion canadensis_codegen_rust/src/impl_serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,17 @@ impl Display for WriteAlignedField<'_> {
PrimitiveType::Boolean => {
writeln!(f, "cursor.write_bool({});", self.field_expr)?
}
PrimitiveType::Byte | PrimitiveType::Utf8 => {
// Same as uint8
Display::fmt(
&CallWriteAligned {
bits: 8,
name: self.field_expr,
as_uint: false,
},
f,
)?;
}
PrimitiveType::Int { bits } => {
Display::fmt(
&CallWriteAligned {
Expand Down Expand Up @@ -301,6 +312,17 @@ impl Display for WriteUnalignedField<'_> {
PrimitiveType::Boolean => {
writeln!(f, "cursor.write_bool({});", self.field_expr)?
}
PrimitiveType::Byte | PrimitiveType::Utf8 => {
// Same as uint8
Display::fmt(
&CallWrite {
bits: 8,
name: self.field_expr,
as_uint: false,
},
f,
)?;
}
PrimitiveType::Int { bits } => Display::fmt(
&CallWrite {
bits: *bits,
Expand Down Expand Up @@ -429,7 +451,7 @@ impl Display for WriteArrayElements<'_> {
)?;
writeln!(f, "}}")
}
PrimitiveType::UInt { bits: 8, .. } => {
PrimitiveType::UInt { bits: 8, .. } | PrimitiveType::Byte | PrimitiveType::Utf8 => {
// Special case for byte arrays
writeln!(f, "cursor.write_bytes(&({})[..]);", self.array_expr)
}
Expand Down
5 changes: 4 additions & 1 deletion canadensis_codegen_rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,9 @@ fn scalar_supports_zero_copy(scalar: &ResolvedScalarType) -> bool {
}
PrimitiveType::Float16 { .. }
| PrimitiveType::Float32 { .. }
| PrimitiveType::Float64 { .. } => true,
| PrimitiveType::Float64 { .. }
| PrimitiveType::Byte
| PrimitiveType::Utf8 => true,
},
ResolvedScalarType::Void { .. } => false,
}
Expand Down Expand Up @@ -624,6 +626,7 @@ fn scalar_to_rust_type(
}
ResolvedScalarType::Primitive(primitive) => match primitive {
PrimitiveType::Boolean => "bool".to_owned(),
PrimitiveType::Byte | PrimitiveType::Utf8 => "u8".to_owned(),
PrimitiveType::Int { bits, .. } => format!("i{}", round_up_integer_size(*bits)),
PrimitiveType::UInt { bits, .. } => format!("u{}", round_up_integer_size(*bits)),
PrimitiveType::Float16 { .. } => "::half::f16".to_owned(),
Expand Down
20 changes: 18 additions & 2 deletions canadensis_codegen_rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate canadensis_codegen_rust;
extern crate canadensis_dsdl_frontend;
extern crate clap;

use canadensis_dsdl_frontend::Package;
use canadensis_dsdl_frontend::{Config, Package};
use clap::{value_parser, Arg, Command};
use std::collections::BTreeMap;
use std::fs::File;
Expand All @@ -28,12 +28,13 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
output_file: output_path,
external_packages,
rustfmt,
config,
} => {
let mut package = Package::new();
for path in input_folders {
package.add_files(path)?;
}
let package = match package.compile_with_warnings() {
let package = match package.compile_with_warnings(&config) {
Ok(package) => package,
Err((e, warnings)) => {
for warning in warnings {
Expand Down Expand Up @@ -103,6 +104,8 @@ enum Args {
external_packages: BTreeMap<Vec<String>, Vec<String>>,
/// Run rustfmt on the generated code
rustfmt: bool,
/// Parser configuration
config: Config,
},
PrintDependencies,
}
Expand Down Expand Up @@ -142,6 +145,15 @@ fn get_args() -> Args {
.long("rustfmt")
.num_args(0)
.help("Run rustfmt to format the generated code")
)
.arg(Arg::new("allow_utf8_and_byte")
.long("unstable-allow-utf8-and-byte")
.num_args(0)
.help("Allow utf8 and byte DSDL types (this option is unstable)")
).arg(Arg::new("forbid_saturated_bool")
.long("unstable-forbid-saturated-bool")
.num_args(0)
.help("Forbid the saturated bool DSDL type (this option is unstable and may become the default)")
))
.subcommand(Command::new("print-dependencies")
.about("Prints the packages that the generated code depends on (for use in Cargo.toml)"));
Expand All @@ -165,6 +177,10 @@ fn get_args() -> Args {
})
.unwrap_or_else(BTreeMap::new),
rustfmt: matches.contains_id("rustfmt"),
config: Config {
allow_utf8_and_byte: matches.contains_id("allow_utf8_and_byte"),
allow_saturated_bool: !matches.contains_id("forbid_saturated_bool"),
},
},
Some(("print-dependencies", _)) => Args::PrintDependencies,
_ => panic!("Unrecognized Subcommand"),
Expand Down
1 change: 1 addition & 0 deletions canadensis_codegen_rust/src/size_bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ impl Display for WriteScalarSize<'_> {
}
ResolvedScalarType::Primitive(primitive) => match primitive {
PrimitiveType::Boolean => write!(f, "1")?,
PrimitiveType::Byte | PrimitiveType::Utf8 => write!(f, "8")?,
PrimitiveType::Int { bits } => write!(f, "{}", *bits)?,
PrimitiveType::UInt { bits, .. } => write!(f, "{}", *bits)?,
PrimitiveType::Float16 { .. } => write!(f, "16")?,
Expand Down
5 changes: 3 additions & 2 deletions canadensis_codegen_rust/tests/compile_fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern crate canadensis_codegen_rust;
extern crate canadensis_dsdl_frontend;

use canadensis_dsdl_frontend::compiled::package::CompiledPackage;
use canadensis_dsdl_frontend::Package;
use canadensis_dsdl_frontend::{Config, Package};
use std::ffi::OsString;
use std::fs;
use std::io;
Expand Down Expand Up @@ -49,7 +49,8 @@ fn compile_fail() -> io::Result<()> {
fn try_compile_package(path: &Path) -> Result<CompiledPackage, canadensis_dsdl_frontend::Error> {
let mut package = Package::new();
package.add_files(path)?;
package.compile()
let config = Config::default();
package.compile(&config)
}

fn try_compile_and_generate_code(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
Expand Down
8 changes: 6 additions & 2 deletions canadensis_codegen_rust/tests/compile_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate canadensis_dsdl_frontend;
use std::path::PathBuf;

use canadensis_dsdl_frontend::compiled::package::CompiledPackage;
use canadensis_dsdl_frontend::Package;
use canadensis_dsdl_frontend::{Config, Package};

/// Checks that this library can compile the Cyphal public regulated data types, Nunavut test
/// types, and a few additional Canadensis test types
Expand Down Expand Up @@ -43,7 +43,11 @@ fn try_compile_package(
for path in paths {
package.add_files(path)?;
}
package.compile()
let config = Config {
allow_utf8_and_byte: true,
allow_saturated_bool: false,
};
package.compile(&config)
}

fn try_compile_and_generate_code(paths: &[PathBuf]) -> Result<(), Box<dyn std::error::Error>> {
Expand Down
5 changes: 5 additions & 0 deletions canadensis_dsdl_frontend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ path = "../canadensis_dsdl_parser"
[dependencies.canadensis_bit_length_set]
version = "0.3.0"
path = "../canadensis_bit_length_set"

[dev-dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
regex = "1.10.5"
4 changes: 2 additions & 2 deletions canadensis_dsdl_frontend/examples/load_package.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate canadensis_dsdl_frontend;
use canadensis_dsdl_frontend::compiled::DsdlKind;
use canadensis_dsdl_frontend::{Error, Package};
use canadensis_dsdl_frontend::{Config, Error, Package};
use std::env;
use std::process;

Expand Down Expand Up @@ -29,7 +29,7 @@ fn run() -> Result<(), Error> {
package.add_files(path)?;
}

let compiled = package.compile()?;
let compiled = package.compile(&Config::default())?;

for (key, compiled_dsdl) in compiled {
println!("{}:", key);
Expand Down
23 changes: 14 additions & 9 deletions canadensis_dsdl_frontend/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::types::expression::convert_type;
use crate::types::{array_length_bits, PrimitiveType, ResolvedScalarType, ResolvedType};
use crate::warning::Warnings;
use canadensis_bit_length_set::BitLengthSet;
use canadensis_dsdl_parser::{Identifier, Span, Statement};
use canadensis_dsdl_parser::{Config, Identifier, Span, Statement};
use once_cell::sync::Lazy;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;
Expand All @@ -32,8 +32,9 @@ static BIT_LENGTH_ZERO: Lazy<BitLengthSet> = Lazy::new(|| BitLengthSet::single(0
///
/// This function returns the compiled DSDL or an error. In either case, it also returns
/// a set of warnings.
pub(crate) fn compile(files: BTreeMap<TypeKey, DsdlFile>) -> CompileOutput {
pub(crate) fn compile(files: BTreeMap<TypeKey, DsdlFile>, config: &Config) -> CompileOutput {
let context = PersistentContext {
config,
pending: files,
done: BTreeMap::new(),
warnings: Warnings::new(),
Expand All @@ -53,14 +54,14 @@ pub(crate) struct CompileOutput {
///
/// They use its functions to collect information about the type currently being compiled, and
/// about other types.
pub(crate) struct CompileContext<'p> {
pub(crate) struct CompileContext<'p, 'c: 'p> {
/// Persistent context and information about other types
persistent: &'p mut PersistentContext,
persistent: &'p mut PersistentContext<'c>,
/// Information about the type currently being compiled
current_file: &'p mut FileState,
}

impl<'p> CompileContext<'p> {
impl<'p, 'c: 'p> CompileContext<'p, 'c> {
/// Returns the constants that have been declared in the current file
///
/// If the current file defines a service type, constants declared in the request section
Expand Down Expand Up @@ -220,15 +221,19 @@ impl<'p> CompileContext<'p> {
}

/// A convenience function to make a `CompileContext`
fn ctx<'p>(p: &'p mut PersistentContext, c: &'p mut FileState) -> CompileContext<'p> {
fn ctx<'p, 'c: 'p>(
p: &'p mut PersistentContext<'c>,
c: &'p mut FileState,
) -> CompileContext<'p, 'c> {
CompileContext {
persistent: p,
current_file: c,
}
}

/// A context used during the compilation process
struct PersistentContext {
struct PersistentContext<'c> {
config: &'c Config,
/// Files that have not been compiled
pending: BTreeMap<TypeKey, DsdlFile>,
/// Files that have been compiled
Expand All @@ -237,7 +242,7 @@ struct PersistentContext {
warnings: Warnings,
}

impl PersistentContext {
impl<'c> PersistentContext<'c> {
fn compile(mut self) -> CompileOutput {
while let Some(key) = self.pending.keys().next().cloned() {
let input = self.pending.remove(&key).unwrap();
Expand Down Expand Up @@ -277,7 +282,7 @@ impl PersistentContext {
let mut state = FileState::new(key.name().path());

let text = input.read()?;
let ast = canadensis_dsdl_parser::parse(&text)?;
let ast = canadensis_dsdl_parser::parse(&text, &self.config)?;

for statement in ast.statements {
match statement {
Expand Down
2 changes: 2 additions & 0 deletions canadensis_dsdl_frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ mod type_key;
pub mod types;
pub mod warning;

pub use canadensis_dsdl_parser::Config;

pub use crate::error::Error;
pub use crate::package::Package;
pub use crate::type_key::{TypeFullName, TypeKey};
4 changes: 2 additions & 2 deletions canadensis_dsdl_frontend/src/operators/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use canadensis_dsdl_parser::Span;

/// Evaluates the attribute operator `expr.attribute`
pub(crate) fn evaluate(
cx: &mut CompileContext<'_>,
cx: &mut CompileContext<'_, '_>,
lhs: Value,
rhs: &str,
span: Span<'_>,
Expand Down Expand Up @@ -87,7 +87,7 @@ fn make_set_min_max_gt_undefined_error(
}

fn evaluate_type_attr(
cx: &mut CompileContext<'_>,
cx: &mut CompileContext<'_, '_>,
ty: Type,
rhs: &str,
span: Span<'_>,
Expand Down
Loading