Skip to content

Commit

Permalink
Add basic DEFAULT support for INTEGER, *STRING and BOOLEANs
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Mar 31, 2021
1 parent 0661dad commit 53d8a00
Show file tree
Hide file tree
Showing 27 changed files with 1,029 additions and 107 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,16 @@ The crate can be used as standalone CLI binary or used as library through its AP
| ...`A..B,...` | ✔️ yes | ✔️ yes | ✔️ yes² | ✔️ yes² | ✔️ yes² | ⚠️ ignored |
| `BOOLEAN` | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
| `OPTIONAL` | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes | ✔️ yes |
| `DEFAULT ...` | ✔️ yes | | | | | |
| ...`INTEGER` | ✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ | ⚠️ ignored |
| ...`*String` | ✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ | ⚠️ ignored |
| ...`BOOLEAN` | ✔️ yes | ✔️ yes | ✔️ yes¹ | ✔️ yes¹ | ✔️ yes¹ | ⚠️ ignored |
| `IMPORTS..FROM..;` | ✔️ yes | | | | | |
| `ObjectIdentifiers` | ✔️ yes | | | | | |
| Value References | ✔️ yes | | | | | |
| ... in Range | ✔️ yes | | | | | |
| ... in Size | ✔️ yes | | | | | |
| ... in Default | ✔️ yes | | | | | |


- ✔️ yes: according to specification
Expand Down
73 changes: 71 additions & 2 deletions asn1rs-model/src/ast/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ use super::range::ident_or_literal_or_punct;
use super::range::IntegerRange;
use super::tag::AttrTag;
use crate::ast::constants::ConstLit;
use crate::model::LiteralValue;
use crate::model::{
Charset, Choice, ChoiceVariant, Enumerated, EnumeratedVariant, Range, Size, Tag, Type,
};
use quote::ToTokens;
use std::fmt::Debug;
use std::fmt::Display;
use std::marker::PhantomData;
use std::ops::Deref;
Expand All @@ -20,6 +23,7 @@ pub(crate) struct AsnAttribute<C: Context> {
pub(crate) tag: Option<Tag>,
pub(crate) consts: Vec<ConstLit>,
pub(crate) extensible_after: Option<String>,
pub(crate) default_value: Option<LiteralValue>,
_c: PhantomData<C>,
}

Expand All @@ -30,6 +34,7 @@ impl<C: Context> AsnAttribute<C> {
tag: None,
consts: Vec::default(),
extensible_after: None,
default_value: None,
_c: Default::default(),
}
}
Expand Down Expand Up @@ -80,6 +85,15 @@ impl<C: Context> Parse for AsnAttribute<C> {

eof_or_comma(input, "Attributes must be separated by comma")?;
}

if cfg!(feature = "debug-proc-macro") {
println!(
"AsnAttribute parse_args end: {:?}/{}",
asn,
input.to_string()
);
}

Ok(asn)
}
}
Expand Down Expand Up @@ -149,6 +163,59 @@ fn parse_type_pre_stepped<'a>(
let inner = parse_type(&content)?;
Ok(Type::Optional(Box::new(inner)))
}
"default" => {
let content;
parenthesized!(content in input);
let span = content.span();
let ctnt = content.to_string();
let inner = parse_type(&content).map_err(|e| {
syn::Error::new(
span,
format!(
"Failed to extract default value type({}): {}",
ctnt,
e.to_string()
),
)
})?;

content.parse::<Token![,]>()?;
let span = content.span();
let ctnt = content.to_string();
let mut default = String::default();
if content.peek(Token![-]) {
content.parse::<Token![-]>()?;
default.push('-');
}

let ident = content
.parse::<syn::Ident>()
.map(|i| i.to_string())
.or_else(|_| {
content
.parse::<syn::Lit>()
.map(|l| l.to_token_stream().to_string())
})
.map_err(|e| {
syn::Error::new(
span,
format!(
"Failed to parse default value literal({}): {}",
ctnt,
e.to_string()
),
)
})?;

Ok(Type::Default(
Box::new(inner),
LiteralValue::try_from_asn_str(&{
default.push_str(&ident);
default
})
.ok_or_else(|| syn::Error::new(span, "Invalid literal value"))?,
))
}
"boolean" => Ok(Type::Boolean),
"sequence_of" | "set_of" => {
let content;
Expand Down Expand Up @@ -259,8 +326,8 @@ impl PrimaryContext for Option<usize> {
}
}

pub trait Context {
type Primary: PrimaryContext;
pub trait Context: Debug {
type Primary: PrimaryContext + Debug;
const EXTENSIBLE_AFTER: bool;
const TAGGABLE: bool;
const CONSTS: bool;
Expand Down Expand Up @@ -294,6 +361,7 @@ impl Context for EnumeratedVariant {
const CONSTS: bool = false;
}

#[derive(Debug)]
pub struct Transparent;
impl Context for Transparent {
type Primary = Type;
Expand All @@ -302,6 +370,7 @@ impl Context for Transparent {
const CONSTS: bool = true;
}

#[derive(Debug)]
pub struct DefinitionHeader(String);
impl Context for DefinitionHeader {
type Primary = Self;
Expand Down
19 changes: 15 additions & 4 deletions asn1rs-model/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ pub fn parse(attr: TokenStream, item: TokenStream) -> TokenStream {

let (definition, item) = match parse_asn_definition(attr, item) {
Ok(v) => v,
Err(e) => return e,
Err(e) => {
println!("Errör: {}", e.to_string());
return e;
}
};

if cfg!(feature = "debug-proc-macro") {
Expand Down Expand Up @@ -108,6 +111,11 @@ pub fn parse_asn_definition(
)
})?;

if cfg!(feature = "debug-proc-macro") {
println!("{:?}", asn);
println!("Matching item {:?}", item);
}

match item {
Item::Struct(strct) if asn.primary.eq_ignore_ascii_case("sequence") => {
parse_sequence_or_set(strct, &asn, attr_span, Type::Sequence)
Expand Down Expand Up @@ -350,9 +358,11 @@ fn parse_and_remove_first_asn_attribute<C: Context>(
attrs: &mut Vec<Attribute>,
) -> Result<AsnAttribute<C>, TokenStream> {
find_and_remove_first_asn_attribute_or_err(span, attrs).and_then(|attribute| {
attribute
.parse_args::<AsnAttribute<C>>()
.map_err(|e| e.to_compile_error())
attribute.parse_args::<AsnAttribute<C>>().map_err(|e| {
println!("parse_args failed {:?}", e);
syn::Error::new(span, e).into_compile_error()
//e.into_compile_error()
})
})
}

Expand All @@ -372,6 +382,7 @@ fn into_asn<C: Context<Primary = Type>>(ty: &syn::Type, mut asn: AsnAttribute<C>
}
asn.primary
},
default: asn.default_value,
}
}

Expand Down
26 changes: 17 additions & 9 deletions asn1rs-model/src/gen/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use self::async_psql::AsyncPsqlInserter;
#[cfg_attr(feature = "legacy-protobuf-codegen", allow(deprecated))]
use self::protobuf::ProtobufSerializer;
use std::convert::Infallible;
use std::fmt::Display;

const KEYWORDS: [&str; 9] = [
"use", "mod", "const", "type", "pub", "enum", "struct", "impl", "trait",
Expand Down Expand Up @@ -191,7 +192,12 @@ impl RustCodeGenerator {
}

for vref in &model.value_references {
scope.raw(&Self::fmt_const(&vref.name, &vref.role, &vref.value, 0));
scope.raw(&Self::fmt_const(
&vref.name,
&vref.role,
&vref.value.as_rust_const_literal(),
0,
));
}

for definition in &model.definitions {
Expand All @@ -206,18 +212,13 @@ impl RustCodeGenerator {
(file, scope.to_string())
}

fn fmt_const(name: &str, r#type: &RustType, value: &str, indent: usize) -> String {
fn fmt_const(name: &str, r#type: &RustType, value: &impl Display, indent: usize) -> String {
format!(
"{}pub const {}: {} = {};",
" ".repeat(indent),
name,
r#type.to_string(),
// TODO this does only support a small variety of constant types
if matches!(r#type, RustType::String(..)) {
Cow::Owned(format!("\"{}\"", value))
} else {
Cow::Borrowed(value)
}
r#type.to_const_lit_string(),
value
)
}

Expand Down Expand Up @@ -426,6 +427,13 @@ impl RustCodeGenerator {
Cow::Borrowed("optional"),
vec![Self::asn_attribute_type(&*inner)],
),
Type::Default(inner, default) => (
Cow::Borrowed("default"),
vec![
Self::asn_attribute_type(&*inner),
default.as_rust_const_literal().to_string(),
],
),
Type::SequenceOf(inner, size) => (
Cow::Borrowed("sequence_of"),
vec![
Expand Down
59 changes: 53 additions & 6 deletions asn1rs-model/src/gen/rust/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl UperSerializer {
}

fn impl_read_fn_header_for_type(function: &mut Function, name: &str, aliased: &RustType) {
if let RustType::Option(_) = aliased {
if aliased.is_optional() {
function.line(&format!(
"let {} = reader.read_bit()?;",
RustCodeGenerator::rust_field_name(name, true)
Expand Down Expand Up @@ -171,6 +171,24 @@ impl UperSerializer {
block.push_block(for_block);
block.line("values");
}
RustType::Default(inner, default) => {
let mut if_block = Block::new(&format!(
"if {}",
field_name
.clone()
.map_or_else(|| "value".into(), |f| f.name().to_string())
));
Self::impl_read_fn_for_type(
&mut if_block,
&inner.to_inner_type_string(),
field_name,
inner,
);
let mut else_block = Block::new("else");
else_block.line(format!("{}.to_owned()", default.as_rust_const_literal()));
block.push_block(if_block);
block.push_block(else_block);
}
RustType::Option(inner) => {
let mut if_block = Block::new(&format!(
"if {}",
Expand Down Expand Up @@ -356,11 +374,21 @@ impl UperSerializer {
}

fn impl_write_fn_header_for_type(function: &mut Function, name: &str, aliased: &RustType) {
if let RustType::Option(_) = aliased {
function.line(&format!(
"writer.write_bit(self.{}.is_some())?;",
RustCodeGenerator::rust_field_name(name, true)
));
match aliased {
RustType::Option(_) => {
function.line(&format!(
"writer.write_bit(self.{}.is_some())?;",
RustCodeGenerator::rust_field_name(name, true)
));
}
RustType::Default(_, default) => {
function.line(&format!(
"writer.write_bit(self.{} != {})?;",
RustCodeGenerator::rust_field_name(name, true),
default.as_rust_const_literal()
));
}
_ => {}
}
}

Expand Down Expand Up @@ -484,6 +512,25 @@ impl UperSerializer {
);
block.push_block(if_block);
}
RustType::Default(inner, default) => {
let mut if_block = Block::new(&format!(
"if {} != {}",
default.as_rust_const_literal(),
field_name
.clone()
.map_or_else(|| "value".into(), |f| f.to_string()),
));
Self::impl_write_fn_for_type(
&mut if_block,
Some(Member::Local(
field_name.map_or_else(|| "value".into(), |f| f.name().to_string()),
false,
false,
)),
inner,
);
block.push_block(if_block);
}
RustType::Complex(_inner, _tag) => {
block.line(format!(
"{}.write_uper(writer)?;",
Expand Down

0 comments on commit 53d8a00

Please sign in to comment.