diff --git a/CHANGELOG.md b/CHANGELOG.md index e4c40ad..e81d9b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## [0.3.0] - 2025-03-13 + +### Enhancements +- Allow using constants defined in the IDL as integers. + ## [0.2.1] - 2025-03-12 ### Fixes diff --git a/Cargo.toml b/Cargo.toml index 22e5d55..6c90c22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,4 @@ strip = true panic = "abort" [workspace.package] -version = "0.2.1" +version = "0.3.0" diff --git a/idlc_ast/Cargo.toml b/idlc_ast/Cargo.toml index b03d7c4..b9a6012 100644 --- a/idlc_ast/Cargo.toml +++ b/idlc_ast/Cargo.toml @@ -14,3 +14,4 @@ idlc_errors = {path = "../idlc_errors" } pest = "2.7.9" pest_derive = "2.7.9" thiserror = "1.0.59" +lazy_static = "1.5.0" diff --git a/idlc_ast/src/idl_grammar.pest b/idlc_ast/src/idl_grammar.pest index c3353c7..148285b 100644 --- a/idlc_ast/src/idl_grammar.pest +++ b/idlc_ast/src/idl_grammar.pest @@ -14,7 +14,7 @@ float_type = @{ "float" ~ ("32" | "64") } primitive_type = @{ (integer_type | float_type) } value = @{ ("-"? ~ "0x" ~ ASCII_HEX_DIGIT+ | "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)?) } -array_size = @{ ASCII_DIGIT+ } +array_size = @{ ASCII_DIGIT+ | ident } bounded_array = { "[" ~ array_size ~ "]" } unbounded_array = { "[" ~ "]" } diff --git a/idlc_ast/src/pst.rs b/idlc_ast/src/pst.rs index dc7d305..e6876b6 100644 --- a/idlc_ast/src/pst.rs +++ b/idlc_ast/src/pst.rs @@ -1,11 +1,22 @@ // Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause +use std::collections::HashMap; use std::{path::PathBuf, rc::Rc}; use pest::{iterators::Pair, Parser}; use pest_derive::Parser; +use lazy_static::lazy_static; +use std::sync::Mutex; + +lazy_static! { + static ref HASHMAP: Mutex> = { + let m = HashMap::new(); + Mutex::new(m) + }; +} + // Import all AST types use super::ast::{ Const, Count, Documentation, Function, FunctionAttribute, Ident, Interface, InterfaceNode, @@ -179,6 +190,7 @@ impl From> for ParamTypeIn { fn from(rule: Pair) -> Self { debug_assert_eq!(rule.as_rule(), Rule::param_type); let mut inner = rule.into_inner(); + let map = HASHMAP.lock().unwrap(); let r#type = Type::from(ast_unwrap!(inner.next())); if let Type::Custom(r#type) = &r#type { if r#type == "buffer" { @@ -190,7 +202,18 @@ impl From> for ParamTypeIn { match pair.as_rule() { Rule::unbounded_array => Self::Array(r#type, None), Rule::bounded_array => { - let array_len: Count = ast_unwrap!(pair.into_inner().as_str().parse()); + let array_val: String = ast_unwrap!(pair.into_inner().as_str().parse()); + let is_decimal = array_val.parse::(); + let array_len = match is_decimal { + Ok(val) => Count::new(val).unwrap(), + Err(_) => { + if let Some(value) = map.get(&array_val) { + Count::new(value.parse::().unwrap()).unwrap() + } else { + idlc_errors::unrecoverable!("Unknown variable {array_val}") + } + } + }; Self::Array(r#type, Some(array_len)) } _ => unreachable!(), @@ -204,6 +227,7 @@ impl From> for ParamTypeOut { fn from(rule: Pair) -> Self { debug_assert_eq!(rule.as_rule(), Rule::param_type); let mut inner = rule.into_inner(); + let map = HASHMAP.lock().unwrap(); let r#type = Type::from(ast_unwrap!(inner.next())); if let Type::Custom(r#type) = &r#type { if r#type == "buffer" { @@ -215,7 +239,18 @@ impl From> for ParamTypeOut { match pair.as_rule() { Rule::unbounded_array => Self::Array(r#type, None), Rule::bounded_array => { - let array_len: Count = ast_unwrap!(pair.into_inner().as_str().parse()); + let array_val: String = ast_unwrap!(pair.into_inner().as_str().parse()); + let is_decimal = array_val.parse::(); + let array_len = match is_decimal { + Ok(val) => Count::new(val).unwrap(), + Err(_) => { + if let Some(value) = map.get(&array_val) { + Count::new(value.parse::().unwrap()).unwrap() + } else { + idlc_errors::unrecoverable!("Unknown variable {array_val}") + } + } + }; Self::Array(r#type, Some(array_len)) } _ => unreachable!(), @@ -256,6 +291,7 @@ fn parse_struct(pair: Pair) -> Rc { let mut struct_pst = pair.into_inner().skip(1); let ident: Ident = ast_unwrap!(struct_pst.next()).into(); let mut fields = Vec::::new(); + let map = HASHMAP.lock().unwrap(); for rule in struct_pst { match rule.as_rule() { Rule::struct_field => { @@ -264,8 +300,19 @@ fn parse_struct(pair: Pair) -> Rc { let next = ast_unwrap!(iter.next()); let (elem, ident) = match next.as_rule() { Rule::bounded_array => { - let array_len: Count = + let array_val: String = ast_unwrap!(next.clone().into_inner().as_str().parse()); + let is_decimal = array_val.parse::(); + let array_len = match is_decimal { + Ok(val) => Count::new(val).unwrap(), + Err(_) => { + if let Some(value) = map.get(&array_val) { + Count::new(value.parse::().unwrap()).unwrap() + } else { + idlc_errors::unrecoverable!("Unknown variable {array_val}") + } + } + }; let ident = ast_unwrap!(iter.next()).as_str().to_string(); (array_len, ident) } @@ -297,7 +344,7 @@ fn parse_const(pair: Pair, allow_undefined_behavior: bool) -> Const { let mut inner = pair.into_inner().skip(1); let ty = ast_unwrap!(inner.next()).as_str(); - let ident = ast_unwrap!(inner.next()).into(); + let ident: Ident = ast_unwrap!(inner.next()).into(); let value = ast_unwrap!(inner.next()).as_str(); let primitive = if allow_undefined_behavior { Primitive::try_from(ty).unwrap() @@ -306,6 +353,8 @@ fn parse_const(pair: Pair, allow_undefined_behavior: bool) -> Const { idlc_errors::unrecoverable!("'{value}' isn't in range for type '{ty}' [{e}]") }) }; + let mut map = HASHMAP.lock().unwrap(); + map.insert(ident.to_string(), value.to_string()); Const { ident, diff --git a/tests/idl/ITest.idl b/tests/idl/ITest.idl index 5ccb089..eea1c07 100644 --- a/tests/idl/ITest.idl +++ b/tests/idl/ITest.idl @@ -27,8 +27,11 @@ struct F2 { uint8 b; }; +const uint32 CONST_VAL = 2; +const uint32 CONST_VAL_INF = 3; + struct ArrInStruct { - uint8[2] a; + uint8[CONST_VAL] a; F2[2] c; uint16 d; }; @@ -62,7 +65,7 @@ interface ITest1 { */ method well_documented_method(in uint32 foo, out uint32 bar); method test_obj_array_in(in ITest1[3] o_in, out uint32 a); - method test_obj_array_out(out ITest1[3] out, out uint32 a); + method test_obj_array_out(out ITest1[CONST_VAL_INF] out, out uint32 a); method objects_in_struct(in ObjInStruct input, out ObjInStruct output); #[optional] method unimplemented(in uint32 foo); // this method should NOT have an implementation and that is OK