use crate::ast::*;
use crate::parser::Rule;
use pest::iterators::{Pair, Pairs};
pub fn build_ast(pairs: Pairs<Rule>) -> File {
let mut statements = Vec::new();
for pair in pairs {
for p in pair.into_inner() {
match p.as_rule() {
Rule::block_def => statements.push(Statement::Block(build_block(p))),
Rule::testbench => statements.push(Statement::Testbench(build_testbench(p))),
Rule::testgroup => statements.push(Statement::Testgroup(build_testgroup(p))),
Rule::piece_def => statements.push(Statement::Piece(build_piece(p))),
_ => (),
}
}
}
File { statements }
}
fn build_block(pair: Pair<Rule>) -> BlockDef {
let mut inner = pair.into_inner();
let name = inner.next().expect("Expected block name").as_str().to_string();
let mut body = Vec::new();
for p in inner {
match p.as_rule() {
Rule::ret_stmt => body.push(BlockStmt::RetAssign(build_ret_stmt(p))),
Rule::pass_stmt => body.push(BlockStmt::PassParams(build_pass_stmt(p))),
Rule::ret_var_stmt => {
let id = p.into_inner().next()
.expect("ret_var_stmt found but identifier missing")
.as_str().to_string();
body.push(BlockStmt::RetVar(id));
},
Rule::block_def => body.push(BlockStmt::NestedBlock(build_block(p))),
_ => (),
}
}
BlockDef { name, params: vec![], body }
}
fn build_ret_stmt(pair: Pair<Rule>) -> RetAssign {
let nodes: Vec<Pair<Rule>> = pair.into_inner().collect();
let target = nodes[0].as_str().to_string();
let width = nodes.iter().find(|n| n.as_rule() == Rule::width_constraint)
.map(|n| parse_width(n.clone()));
let expr = nodes.iter().find(|n| n.as_rule() == Rule::expr)
.expect("RetStmt expression missing").as_str().to_string();
RetAssign { target, expr, width }
}
fn build_pass_stmt(pair: Pair<Rule>) -> PassParams {
let mut inner = pair.into_inner();
let inst_name = inner.next().expect("PassParams inst_name missing").as_str().to_string();
let block_type = inner.next().expect("PassParams type missing").as_str().to_string();
let params = inner.map(|p| p.as_str().to_string()).collect();
PassParams { inst_name, block_type, params }
}
fn build_piece(pair: Pair<Rule>) -> PieceDef {
let mut inner = pair.into_inner();
let name = inner.next().expect("Piece name missing").as_str().to_string();
let members = inner.map(|p| {
let mut m = p.into_inner();
(m.next().expect("Member dir missing").as_str().to_string(), m.next().expect("Member name missing").as_str().to_string())
}).collect();
PieceDef { name, members }
}
fn build_testbench(pair: Pair<Rule>) -> TestbenchDef {
let mut inner = pair.into_inner();
let name = inner.next().expect("TB name missing").as_str().to_string();
let target = inner.next().expect("TB target missing").as_str().to_string();
let _getvars = inner.next();
let when_block = inner.next().expect("TB block missing");
let mut body = Vec::new();
for p in when_block.into_inner() {
body.push(parse_verif_cmd(p));
}
TestbenchDef { name, target, body }
}
fn parse_verif_cmd(pair: Pair<Rule>) -> VerifCmd {
match pair.as_rule() {
Rule::expect_cmd => {
let mut i = pair.into_inner();
VerifCmd::Expect {
time: i.next().unwrap().as_str().parse().unwrap(),
lhs: i.next().unwrap().as_str().to_string(),
rhs: i.next().unwrap().as_str().to_string()
}
},
Rule::pulse_cmd => {
let mut i = pair.into_inner();
VerifCmd::Pulse {
len: i.next().unwrap().as_str().to_string(),
gap: i.next().unwrap().as_str().to_string()
}
},
Rule::watch_cmd => {
let mut i = pair.into_inner();
let time_a = i.next().unwrap().as_str().parse().unwrap();
let lhs = i.next().unwrap().as_str().to_string();
let rhs = i.next().unwrap().as_str().to_string();
let time_b = i.next().unwrap().as_str().parse().unwrap();
let out_arg = i.next().unwrap();
let out = if out_arg.as_rule() == Rule::string_literal {
OutTarget::Literal(out_arg.as_str().to_string())
} else {
OutTarget::Variable(out_arg.as_str().to_string())
};
VerifCmd::Watchfor { time_a, lhs, rhs, time_b, out }
},
Rule::write_cmd => {
let mut i = pair.into_inner();
VerifCmd::Write(WriteStmt {
target: i.next().unwrap().as_str().to_string(),
val: i.next().unwrap().as_str().to_string()
})
},
Rule::put_stmt => VerifCmd::Put(build_put(pair)),
_ => unreachable!(),
}
}
pub fn build_put(pair: Pair<Rule>) -> PutStmt {
let nodes: Vec<Pair<Rule>> = pair.into_inner().collect();
let target = nodes[0].as_str().to_string();
let op = nodes[1].as_str().to_string();
let width = nodes.iter().find(|n| n.as_rule() == Rule::width_constraint)
.map(|n| parse_width(n.clone()));
let expr = nodes.iter().find(|n| n.as_rule() == Rule::expr)
.expect("Put expr missing").as_str().to_string();
PutStmt { target, op, expr, width }
}
fn build_testgroup(pair: Pair<Rule>) -> TestGroupDef {
let mut inner = pair.into_inner();
let name = inner.next().expect("TG name missing").as_str().to_string();
let mut items = Vec::new();
for p in inner {
match p.as_rule() {
Rule::do_stmt => items.push(GroupItem::Do(p.into_inner().next().unwrap().as_str().to_string())),
Rule::same_block => items.push(GroupItem::Same(p.into_inner().map(|x| x.into_inner().next().unwrap().as_str().to_string()).collect())),
_ => (),
}
}
TestGroupDef { name, items }
}
fn parse_width(pair: Pair<Rule>) -> WidthConstraint {
let mut inner = pair.into_inner();
WidthConstraint { msb: inner.next().unwrap().as_str().parse().unwrap(), lsb: inner.next().unwrap().as_str().parse().unwrap() }
}