Skip to content
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

adding support do declare 'instr' interface fields #11

Merged
merged 1 commit into from
Feb 1, 2024
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: 8 additions & 2 deletions lib/velosilexer/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ pub enum VelosiKeyword {
Mem,
/// field that is a register
Reg,
/// field that is a memory-mapped regsiter
/// field that is a memory-mapped registers
Mmio,
/// a special instruction that is being executed
Instr,

//
// interface descriptions
Expand All @@ -108,7 +110,7 @@ pub enum VelosiKeyword {
//
// control flow and expressions
//
/// conditional statemt
/// conditional statement
If,
/// conditional else branch
Else,
Expand Down Expand Up @@ -189,6 +191,7 @@ impl VelosiKeyword {
VelosiKeyword::Mem => "mem",
VelosiKeyword::Reg => "reg",
VelosiKeyword::Mmio => "mmio",
VelosiKeyword::Instr => "instr",

// interface descriptions
VelosiKeyword::ReadActions => "ReadActions",
Expand Down Expand Up @@ -256,6 +259,7 @@ impl<'a> TryFrom<&'a str> for VelosiKeyword {
"reg" => Ok(VelosiKeyword::Reg),
"mem" => Ok(VelosiKeyword::Mem),
"mmio" => Ok(VelosiKeyword::Mmio),
"instr" => Ok(VelosiKeyword::Instr),
// interface descriptions
"ReadActions" => Ok(VelosiKeyword::ReadActions),
"WriteActions" => Ok(VelosiKeyword::WriteActions),
Expand Down Expand Up @@ -702,6 +706,8 @@ fn test_enum_str() {
assert_eq!(VelosiKeyword::Reg.as_str(), "reg");
assert_eq!("mmio".try_into(), Ok(VelosiKeyword::Mmio));
assert_eq!(VelosiKeyword::Mmio.as_str(), "mmio");
assert_eq!("instr".try_into(), Ok(VelosiKeyword::Instr));
assert_eq!(VelosiKeyword::Instr.as_str(), "instr");

assert_eq!("ReadActions".try_into(), Ok(VelosiKeyword::ReadActions));
assert_eq!(VelosiKeyword::ReadActions.as_str(), "ReadActions");
Expand Down
115 changes: 113 additions & 2 deletions src/parser/interface/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ use crate::error::{IResult, VelosiParserErrBuilder};
/// library internal includes
use crate::parser::terminals::*;
use crate::parsetree::{
VelosiParseTreeIdentifier, VelosiParseTreeInterfaceField, VelosiParseTreeInterfaceFieldMemory,
VelosiParseTreeIdentifier, VelosiParseTreeInterfaceField,
VelosiParseTreeInterfaceFieldInstruction, VelosiParseTreeInterfaceFieldMemory,
VelosiParseTreeInterfaceFieldMmio, VelosiParseTreeInterfaceFieldNode,
VelosiParseTreeInterfaceFieldRegister,
};
Expand Down Expand Up @@ -77,7 +78,7 @@ use crate::{VelosiParserErr, VelosiTokenStream};
pub fn ifacefield(
input: VelosiTokenStream,
) -> IResult<VelosiTokenStream, VelosiParseTreeInterfaceField> {
alt((memoryfield, registerfield, mmiofield))(input)
alt((memoryfield, registerfield, mmiofield, instrfield))(input)
}

/// Parses and consumes a register interface field definition
Expand Down Expand Up @@ -244,6 +245,58 @@ pub fn mmiofield(
Ok((i3, VelosiParseTreeInterfaceField::Mmio(res)))
}

/// Parses and consumes a instr interface field definition
///
/// # Arguments
///
/// * `input` - input token stream to be parsed
///
/// # Results
///
/// * Ok: The parser succeeded. The return value is a tuple of the remaining input and the
/// recognized mmio field as a parse tree node.
/// * Err: The parser did not succeed. The return value indicates whether this is:
///
/// * Error: a recoverable error indicating that the parser did not recognize the input but
/// another parser might, or
/// * Failure: a fatal failure indicating the parser recognized the input but failed to parse it
/// and that another parser would fail.
///
/// # Grammar
///
/// `INSTRFIELD := KW_INSTR LBRAK NUM RBRACK LBRACE SEPLIST(COMMA, IFACEFIELDBODY) RBRACE`
///
pub fn instrfield(
input: VelosiTokenStream,
) -> IResult<VelosiTokenStream, VelosiParseTreeInterfaceField> {
let mut loc = input.clone();

// if we have the instr keyword
let (i1, _) = kw_instr(input)?;

let (i2, name) = cut(ident)(i1)?;

let (i3, nodes) = opt(delimited(
lbrace,
terminated(separated_list0(comma, interfacefieldbody), opt(comma)),
cut(rbrace),
))(i2)?;

loc.span_until_start(&i3);

let nodes = if let Some(nodes) = nodes {
if nodes.is_empty() {
return Err(empty_field_err(i3));
}
nodes
} else {
Vec::new()
};

let res = VelosiParseTreeInterfaceFieldInstruction::with_loc(name, nodes, loc);
Ok((i3, VelosiParseTreeInterfaceField::Instruction(res)))
}

fn empty_field_err(loc: VelosiTokenStream) -> Err<VelosiParserErr> {
let errmsg = "empty interface field block";
let hint = "remove the block or fill it in explicitly";
Expand Down Expand Up @@ -568,3 +621,61 @@ fn test_mmio_field_fail_error_messages() {
test_parse_and_compare_file_fail!("interface/parts/mmiofield_01_field_info_wrong", mmiofield);
test_parse_and_compare_file_fail!("interface/parts/mmiofield_02_field_info_wrong_2", mmiofield);
}

#[test]
fn test_instr_field_ok() {
test_parse_and_compare_ok!(
"instr foo { Layout {} }",
instrfield,
"instr foo {\n Layout {\n },\n}"
);
// trailing comma is ok
test_parse_and_compare_ok!(
"instr foo { Layout {}, }",
instrfield,
"instr foo {\n Layout {\n },\n}"
);
// it's ok to have the elements twice
test_parse_and_compare_ok!(
"instr foo { Layout {}, Layout {}, }",
instrfield,
"instr foo {\n Layout {\n },\n Layout {\n },\n}"
);

test_parse_and_compare_ok!(
"instr foo { WriteActions {}, WriteActions {}, }",
instrfield,
"instr foo {\n WriteActions {\n },\n WriteActions {\n },\n}"
);

test_parse_and_compare_ok!(
"instr foo { ReadActions {}, ReadActions {}, }",
instrfield,
"instr foo {\n ReadActions {\n },\n ReadActions {\n },\n}"
);
// different orders of the body elements are ok
test_parse_and_compare_ok!(
"instr foo { Layout {}, WriteActions{}, ReadActions{} }",
instrfield,
"instr foo {\n Layout {\n },\n WriteActions {\n },\n ReadActions {\n },\n}"
);
test_parse_and_compare_ok!(
"instr foo { ReadActions {}, Layout {}, WriteActions{}, }",
instrfield,
"instr foo {\n ReadActions {\n },\n Layout {\n },\n WriteActions {\n },\n}"
);
test_parse_and_compare_ok!(
"instr foo { WriteActions {}, Layout {}, ReadActions{} }",
instrfield,
"instr foo {\n WriteActions {\n },\n Layout {\n },\n ReadActions {\n },\n}"
);
}

#[test]
fn test_instr_field_fail() {
// empty field definition
test_parse_and_check_fail!("instr foo {}", instrfield);

// parameters
test_parse_and_check_fail!("instr foo [8]", instrfield);
}
1 change: 1 addition & 0 deletions src/parser/terminals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ keywordparser!(pub kw_mapdef, VelosiKeyword::Map);
keywordparser!(pub kw_mem, VelosiKeyword::Mem);
keywordparser!(pub kw_reg, VelosiKeyword::Reg);
keywordparser!(pub kw_mmio, VelosiKeyword::Mmio);
keywordparser!(pub kw_instr, VelosiKeyword::Instr);

keywordparser!(pub kw_readaction, VelosiKeyword::ReadActions);
keywordparser!(pub kw_writeaction, VelosiKeyword::WriteActions);
Expand Down
65 changes: 65 additions & 0 deletions src/parsetree/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,69 @@ impl Debug for VelosiParseTreeInterfaceFieldRegister {
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Interface Instruction Field
///////////////////////////////////////////////////////////////////////////////////////////////////

/// Represents a instruction interface field
#[derive(PartialEq, Eq, Clone)]
pub struct VelosiParseTreeInterfaceFieldInstruction {
/// the identifer of the field
pub name: VelosiParseTreeIdentifier,
/// nodes of the field
pub nodes: Vec<VelosiParseTreeInterfaceFieldNode>,
/// location of the field in the source file
pub loc: VelosiTokenStream,
}

impl VelosiParseTreeInterfaceFieldInstruction {
/// constructs a new register interface field
pub fn with_loc(
name: VelosiParseTreeIdentifier,
nodes: Vec<VelosiParseTreeInterfaceFieldNode>,
loc: VelosiTokenStream,
) -> Self {
Self { name, nodes, loc }
}

/// constructs a new register interface field with default location
pub fn new(
name: VelosiParseTreeIdentifier,
nodes: Vec<VelosiParseTreeInterfaceFieldNode>,
) -> Self {
Self::with_loc(name, nodes, VelosiTokenStream::default())
}
}

/// Implementation of [Display] for [VelosiParseTreeInterfaceFieldInstruction]
impl Display for VelosiParseTreeInterfaceFieldInstruction {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "instr {}", self.name)?;
if !self.nodes.is_empty() {
writeln!(f, " {{")?;
for node in &self.nodes {
let formatted = format!("{node}");
for (i, l) in formatted.lines().enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(f, " {l}")?;
}
writeln!(f, ",")?;
}
write!(f, "}}")?;
}
Ok(())
}
}

/// Implementation of [Debug] for [VelosiParseTreeInterfaceFieldInstruction]
impl Debug for VelosiParseTreeInterfaceFieldInstruction {
fn fmt(&self, format: &mut Formatter) -> FmtResult {
Display::fmt(&self, format)
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Interface Fields
///////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -495,6 +558,7 @@ pub enum VelosiParseTreeInterfaceField {
Memory(VelosiParseTreeInterfaceFieldMemory),
Mmio(VelosiParseTreeInterfaceFieldMmio),
Register(VelosiParseTreeInterfaceFieldRegister),
Instruction(VelosiParseTreeInterfaceFieldInstruction),
}

/// Implementation of [Display] for [VelosiParseTreeInterfaceField]
Expand All @@ -505,6 +569,7 @@ impl Display for VelosiParseTreeInterfaceField {
Memory(field) => Display::fmt(field, f),
Mmio(field) => Display::fmt(field, f),
Register(field) => Display::fmt(field, f),
Instruction(field) => Display::fmt(field, f),
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/parsetree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ pub use identifier::VelosiParseTreeIdentifier;
pub use import::VelosiParseTreeImport;
pub use interface::{
VelosiParseTreeInterface, VelosiParseTreeInterfaceAction, VelosiParseTreeInterfaceActions,
VelosiParseTreeInterfaceField, VelosiParseTreeInterfaceFieldMemory,
VelosiParseTreeInterfaceFieldMmio, VelosiParseTreeInterfaceFieldNode,
VelosiParseTreeInterfaceFieldRegister, VelosiParseTreeInterfaceLayout,
VelosiParseTreeInterfaceField, VelosiParseTreeInterfaceFieldInstruction,
VelosiParseTreeInterfaceFieldMemory, VelosiParseTreeInterfaceFieldMmio,
VelosiParseTreeInterfaceFieldNode, VelosiParseTreeInterfaceFieldRegister,
VelosiParseTreeInterfaceLayout,
};
pub use map::{
VelosiParseTreeMap, VelosiParseTreeMapElement, VelosiParseTreeMapExplicit,
Expand Down
Loading