Skip to content

Commit

Permalink
we can parse now
Browse files Browse the repository at this point in the history
  • Loading branch information
EclecticGriffin committed Jan 13, 2025
1 parent 3c22bce commit 615e939
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 34 deletions.
67 changes: 67 additions & 0 deletions calyx-frontend/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,80 @@ impl From<InternalAttr> for Attribute {
Eq,
Debug,
strum_macros::Display,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum SetAttr {
#[strum(serialize = "pos")]
/// Source location position for this node
Pos,
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum SetAttribute {
Set(SetAttr),
Unknown(Id),
}

impl Ord for SetAttribute {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(SetAttribute::Set(s1), SetAttribute::Set(s2)) => s1.cmp(s2),
(SetAttribute::Set(_), SetAttribute::Unknown(_)) => {
std::cmp::Ordering::Less
}
(SetAttribute::Unknown(_), SetAttribute::Set(_)) => {
std::cmp::Ordering::Greater
}
(SetAttribute::Unknown(id1), SetAttribute::Unknown(id2)) => {
id1.as_ref().cmp(id2.as_ref())
}
}
}
}

impl PartialOrd for SetAttribute {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl From<Id> for SetAttribute {
fn from(v: Id) -> Self {
Self::Unknown(v)
}
}

impl From<SetAttr> for SetAttribute {
fn from(v: SetAttr) -> Self {
Self::Set(v)
}
}

impl std::fmt::Display for SetAttribute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SetAttribute::Set(set_attr) => set_attr.fmt(f),
SetAttribute::Unknown(id) => id.fmt(f),
}
}
}

impl FromStr for SetAttribute {
type Err = Error;
fn from_str(s: &str) -> CalyxResult<Self> {
if let Ok(s) = SetAttr::from_str(s) {
Ok(SetAttribute::Set(s))
} else {
// Reject attributes that all caps since those are reserved for internal attributes
if s.to_uppercase() == s {
return Err(Error::misc(format!("Invalid attribute: {}. All caps attributes are reserved for internal use.", s)));
}
Ok(SetAttribute::Unknown(s.into()))
}
}
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
Expand Down
95 changes: 70 additions & 25 deletions calyx-frontend/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Attribute;
use crate::{attribute::SetAttr, InlineAttributes};
use crate::{attribute::SetAttribute, InlineAttributes};
use calyx_utils::{CalyxResult, GPosIdx, WithPos};
use itertools::Itertools;
use linked_hash_map::LinkedHashMap;
Expand All @@ -10,7 +10,7 @@ use std::{collections::HashMap, convert::TryFrom};
/// Attribute information stored on the Heap
struct HeapAttrInfo {
attrs: LinkedHashMap<Attribute, u64>,
set_attrs: HashMap<SetAttr, VecSet<u32, 4>>,
set_attrs: HashMap<SetAttribute, VecSet<u32, 4>>,
span: GPosIdx,
}

Expand All @@ -24,19 +24,54 @@ pub struct Attributes {
hinfo: Box<HeapAttrInfo>,
}

impl TryFrom<Vec<(Attribute, u64)>> for Attributes {
pub enum ParseAttributeWrapper {
Attribute(Attribute, u64),
Set(SetAttribute, Vec<u32>),
}

impl From<(Attribute, u64)> for ParseAttributeWrapper {
fn from(value: (Attribute, u64)) -> Self {
Self::Attribute(value.0, value.1)
}
}

impl From<(SetAttribute, Vec<u32>)> for ParseAttributeWrapper {
fn from(value: (SetAttribute, Vec<u32>)) -> Self {
Self::Set(value.0, value.1)
}
}

impl TryFrom<Vec<ParseAttributeWrapper>> for Attributes {
type Error = calyx_utils::Error;

fn try_from(v: Vec<(Attribute, u64)>) -> CalyxResult<Self> {
fn try_from(v: Vec<ParseAttributeWrapper>) -> CalyxResult<Self> {
let mut attrs = Attributes::default();
for (k, v) in v {
if attrs.has(k) {
return Err(Self::Error::malformed_structure(format!(
"Multiple entries for attribute: {}",
k
)));

for item in v {
match item {
ParseAttributeWrapper::Attribute(k, v) => {
if attrs.has(k) {
return Err(Self::Error::malformed_structure(format!(
"Multiple entries for attribute: {}",
k
)));
}
attrs.insert(k, v);
}
ParseAttributeWrapper::Set(set_attr, vec) => {
if attrs.hinfo.set_attrs.contains_key(&set_attr) {
return Err(Self::Error::malformed_structure(format!(
"Multiple entries for attribute: {}",
set_attr
)));
}

attrs
.hinfo
.set_attrs
.insert(set_attr, vec.into_iter().collect());
}
}
attrs.insert(k, v);
}
Ok(attrs)
}
Expand Down Expand Up @@ -95,8 +130,11 @@ impl Attributes {
}
}

pub fn get_set(&self, key: SetAttr) -> Option<&VecSet<u32>> {
self.hinfo.set_attrs.get(&key)
pub fn get_set<S>(&self, key: S) -> Option<&VecSet<u32>>
where
S: Into<SetAttribute>,
{
self.hinfo.set_attrs.get(&key.into())
}

/// Check if an attribute key has been set
Expand Down Expand Up @@ -179,18 +217,25 @@ impl Attributes {
.iter()
.map(|(k, v)| fmt(k.to_string(), *v))
.chain(self.inl.iter().map(|k| fmt(k.as_ref().to_string(), 1)))
.chain(self.hinfo.set_attrs.iter().filter_map(|(k, v)| {
if v.is_empty() {
None
} else {
let formatted = set_fmt(k.to_string(), v.as_slice());
if formatted.is_empty() {
None
} else {
Some(formatted)
}
}
}))
.chain(
self.hinfo
.set_attrs
.iter()
.sorted_by_key(|(k, _)| *k)
.filter_map(|(k, v)| {
if v.is_empty() {
None
} else {
let formatted =
set_fmt(k.to_string(), v.as_slice());
if formatted.is_empty() {
None
} else {
Some(formatted)
}
}
}),
)
.collect::<Vec<_>>()
.join(sep)
}
Expand Down
31 changes: 25 additions & 6 deletions calyx-frontend/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ use super::ast::{
self, BitNum, Control, GuardComp as GC, GuardExpr, NumType, StaticGuardExpr,
};
use super::Attributes;
use crate::{Attribute, Direction, PortDef, Primitive, Width};
use crate::{
attribute::{SetAttr, SetAttribute},
attributes::ParseAttributeWrapper,
Attribute, Direction, PortDef, Primitive, Width,
};
use calyx_utils::{self, float, CalyxResult, Id, PosString};
use calyx_utils::{FileIdx, GPosIdx, GlobalPositionTable};
use pest::pratt_parser::{Assoc, Op, PrattParser};
Expand Down Expand Up @@ -367,10 +371,14 @@ impl CalyxParser {
}

// ================ Attributes =====================
fn attribute(input: Node) -> ParseResult<(Attribute, u64)> {
fn attribute(input: Node) -> ParseResult<ParseAttributeWrapper> {
match_nodes!(
input.clone().into_children();
[string_lit(key), bitwidth(num)] => Attribute::from_str(key.as_ref()).map(|attr| (attr, num)).map_err(|e| input.error(format!("{:?}", e)))
[string_lit(key), bitwidth(num)] => Attribute::from_str(key.as_ref()).map(|attr| (attr, num).into()).map_err(|e| input.error(format!("{:?}", e))),
[string_lit(key), attr_set(nums)] => {
let attr = SetAttribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e)))?;
Ok((attr, nums).into())
}
)
}
fn attributes(input: Node) -> ParseResult<Attributes> {
Expand Down Expand Up @@ -405,6 +413,13 @@ impl CalyxParser {
))
}

fn attr_set(input: Node) -> ParseResult<Vec<u32>> {
Ok(match_nodes!(
input.into_children();
[bitwidth(num)..] => num.into_iter().map(|n| {let n_32: u32 = n.try_into().expect("set values must fit in a u32"); n_32}).collect()
))
}

fn latency_annotation(input: Node) -> ParseResult<std::num::NonZeroU64> {
let num = match_nodes!(
input.clone().into_children();
Expand All @@ -417,11 +432,15 @@ impl CalyxParser {
}
}

fn at_attribute(input: Node) -> ParseResult<(Attribute, u64)> {
fn at_attribute(input: Node) -> ParseResult<ParseAttributeWrapper> {
match_nodes!(
input.clone().into_children();
[identifier(key), attr_val(num)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e))).map(|attr| (attr, num)),
[identifier(key)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e))).map(|attr| (attr, 1)),
[identifier(key), attr_val(num)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e))).map(|attr| (attr, num).into()),
[identifier(key), attr_set(nums)] => {
let attr = SetAttribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e)))?;
Ok((attr, nums).into())
},
[identifier(key)] => Attribute::from_str(key.as_ref()).map_err(|e| input.error(format!("{:?}", e))).map(|attr| (attr, 1).into()),
)
}

Expand Down
10 changes: 7 additions & 3 deletions calyx-frontend/src/syntax.pest
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,13 @@ static_wire = {

// =========== Attribute parsing ===============

attr_set = {
"{" ~ bitwidth ~ ("," ~ bitwidth)* ~ "}"
}

// <"static" = 1> style annotation
attribute = {
string_lit ~ "=" ~ bitwidth
string_lit ~ "=" ~ (bitwidth | attr_set)
}
latency_annotation = {
"<" ~ bitwidth ~ ">"
Expand All @@ -270,7 +274,7 @@ attr_val = {
"(" ~ bitwidth ~ ")"
}
at_attribute = {
"@" ~ identifier ~ attr_val?
"@" ~ identifier ~ (attr_val | attr_set)?
}
at_attributes = {
at_attribute*
Expand Down Expand Up @@ -385,4 +389,4 @@ control = {
any_char = { ANY }
metadata_char = ${ !"}#" ~ any_char }

metadata = ${ ^"metadata" ~ WHITESPACE* ~ "#{" ~ metadata_char* ~ "}#"}
metadata = ${ ^"metadata" ~ WHITESPACE* ~ "#{" ~ metadata_char* ~ "}#"}
20 changes: 20 additions & 0 deletions tests/parsing/set_attributes.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import "primitives/core.futil";
import "primitives/binary_operators.futil";
component main(@foo(32) @go_port in: 32, go: 1, clk: 1, @interval @go go0: 1, @clk clk0: 1, @reset reset: 1) -> (@interval(0) out: 32, done: 1, @done done0: 1) {
cells {
@my_other_set{3240189, 123, 2} r = std_reg(32);
@my_set{32} le = std_le(32);
}
wires {
group upd<"stable"=1, "pos"={1, 4, 8}, "my_z"={4}> {
@dead upd[done] = r.done;
}
comb group cond<"promotable"=0> {
}
}
control {
@pos{2, 5, 100000} @other{1} @z{2, 3, 4} while le.out with cond {
upd;
}
}
}

0 comments on commit 615e939

Please sign in to comment.