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

Implement gate modifiers #79

Merged
merged 6 commits into from
Jan 29, 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
33 changes: 11 additions & 22 deletions crates/oq3_parser/src/grammar/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ pub(crate) fn expr_no_struct(p: &mut Parser<'_>) {

// GJL made public. remove visibility
pub(crate) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
// dbg!(p.current());
if p.eat(T![;]) {
return;
}
Expand Down Expand Up @@ -168,7 +167,8 @@ enum Associativity {
fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) {
use Associativity::*;
// It seems that return value is never checked for `NOT_AN_OP`
const NOT_AN_OP: (u8, SyntaxKind, Associativity) = (0, T![@], Left);
// r-a had @ for not an op. But we use triple dot
const NOT_AN_OP: (u8, SyntaxKind, Associativity) = (0, T![...], Left);
match p.current() {
T![|] if p.at(T![||]) => (3, T![||], Left),
T![|] if p.at(T![|=]) => (1, T![|=], Right),
Expand Down Expand Up @@ -225,13 +225,8 @@ fn expr_bp(
return None;
}
let lhs_result = lhs(p, r);
// dbg!(&lhs_result);
let mut lhs = match lhs_result {
Some((lhs, blocklike, got_call)) => {
if got_call {
m.abandon(p);
return None;
}
Some((lhs, blocklike)) => {
let lhs = lhs.extend_to(p, m);
if r.prefer_stmt && blocklike.is_block() {
return Some((lhs, BlockLike::Block));
Expand Down Expand Up @@ -281,7 +276,7 @@ const LHS_FIRST: TokenSet =
atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-], T![_]]));

// Handles only prefix and postfix expressions?? Not binary infix?
fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike, bool)> {
fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
let m;
// Unary operators. In OQ3 should be ~ ! -, In r-a this is * ! -
let kind = match p.current() {
Expand All @@ -292,15 +287,15 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik
}
_ => {
let (lhs, blocklike) = atom::atom_expr(p, r)?;
let (cm, block_like, got_call) =
let (cm, block_like) =
postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
return Some((cm, block_like, got_call));
return Some((cm, block_like));
}
};
// parse the interior of the unary expression
expr_bp(p, None, r, 255);
let cm = m.complete(p, kind);
Some((cm, BlockLike::NotBlock, false))
Some((cm, BlockLike::NotBlock))
}

fn postfix_expr(
Expand All @@ -311,8 +306,7 @@ fn postfix_expr(
// `while true {break}; ();`
mut block_like: BlockLike,
mut allow_calls: bool,
) -> (CompletedMarker, BlockLike, bool) {
let mut got_call = false;
) -> (CompletedMarker, BlockLike) {
loop {
lhs = match p.current() {
// test stmt_postfix_expr_ambiguity
Expand All @@ -323,10 +317,7 @@ fn postfix_expr(
// [] => {}
// }
// }
T!['('] if allow_calls => {
got_call = true;
call_expr(p, lhs)
}
T!['('] if allow_calls => call_expr(p, lhs),
T!['['] if allow_calls => match lhs.kind() {
IDENTIFIER => indexed_identifer(p, lhs),
_ => index_expr(p, lhs),
Expand All @@ -336,12 +327,10 @@ fn postfix_expr(
allow_calls = true;
block_like = BlockLike::NotBlock;
}
(lhs, block_like, got_call)
(lhs, block_like)
}

// Consumes either a function (def) call, or a gate call.
// expressions::gate_call_stmt also consumes gate calls in a different context.
// I think the present function gets all gate calls that include params in parens.
fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
assert!(p.at(T!['(']));
let m = lhs.precede(p);
Expand All @@ -351,7 +340,7 @@ fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
// If there is no identifier, it is a function call.
if matches!(p.current(), IDENT | HARDWAREIDENT) {
params::arg_list_gate_call_qubits(p);
return m.complete(p, GATE_CALL_STMT);
return m.complete(p, GATE_CALL_EXPR);
}
m.complete(p, CALL_EXPR)
}
Expand Down
94 changes: 92 additions & 2 deletions crates/oq3_parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
T![return],
T![while],
T![measure],
T![inv],
T![ctrl],
T![negctrl],
T![pow],
]));

pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]);
Expand Down Expand Up @@ -77,9 +81,13 @@ pub(super) fn atom_expr(
T![return] => return_expr(p),
T!['{'] => block_expr(p),
T![for] => for_expr(p, None),
T![inv] => inv_modifier_expr(p),
T![pow] => pow_modifier_expr(p),
T![ctrl] => ctrl_modifier_expr(p),
T![negctrl] => negctrl_modifier_expr(p),
// FIXME: This is the simplest gate call. Need to cover
// `mygate(myparam) q1, q2;` as well.
// IDENT if la == IDENT => gate_call_expr(p),
IDENT if la == IDENT => gate_call_expr(p),
IDENT if (la == T![=] && p.nth(2) != T![=]) => grammar::items::assignment_statement(p),
// FIXME: An identifer bound by the user in the program.
// Need to handle more than identifier.
Expand All @@ -98,6 +106,88 @@ pub(super) fn atom_expr(
Some((done, blocklike))
}

fn inv_modifier_expr(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
p.bump(T![inv]);
if p.at(T![@]) {
p.bump(T![@]);
} else if p.at(T!['(']) {
p.error("Modifier `inv` accepts no parameter. Expecting `@`");
} else {
p.error("Expecting `@`");
}
maybe_modified_gate_call_expr(p);
m.complete(p, INV_GATE_CALL_EXPR)
}

fn pow_modifier_expr(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
assert!(p.at(T![pow]));
p.bump(T![pow]);
if p.at(T!['(']) {
let m1 = p.start();
p.expect(T!['(']);
expressions::expr(p);
p.expect(T![')']);
m1.complete(p, PAREN_EXPR);
} else {
p.error("expecting argument to pow gate modifier");
}
p.expect(T![@]);
maybe_modified_gate_call_expr(p);
m.complete(p, POW_GATE_CALL_EXPR)
}

fn ctrl_modifier_expr(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
p.bump(T![ctrl]);
if p.at(T!['(']) {
let m1 = p.start();
p.expect(T!['(']);
expressions::expr(p);
p.expect(T![')']);
m1.complete(p, PAREN_EXPR);
}
p.expect(T![@]);
maybe_modified_gate_call_expr(p);
m.complete(p, CTRL_GATE_CALL_EXPR)
}

fn negctrl_modifier_expr(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
p.bump(T![negctrl]);
if p.at(T!['(']) {
let m1 = p.start();
p.expect(T!['(']);
expressions::expr(p);
p.expect(T![')']);
m1.complete(p, PAREN_EXPR);
}
p.expect(T![@]);
maybe_modified_gate_call_expr(p);
m.complete(p, NEG_CTRL_GATE_CALL_EXPR)
}

fn maybe_modified_gate_call_expr(p: &mut Parser<'_>) -> CompletedMarker {
match p.current() {
T![inv] => inv_modifier_expr(p),
T![pow] => pow_modifier_expr(p),
T![ctrl] => ctrl_modifier_expr(p),
T![negctrl] => negctrl_modifier_expr(p),
_ => gate_call_expr(p),
}
}

fn gate_call_expr(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
identifier(p); // name of gate
if p.at(T!['(']) {
expressions::call_arg_list(p);
}
params::arg_list_gate_call_qubits(p);
m.complete(p, GATE_CALL_EXPR)
}

fn measure_expression(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
p.bump(T![measure]);
Expand All @@ -118,7 +208,7 @@ fn measure_expression(p: &mut Parser<'_>) -> CompletedMarker {
// FIXME: changed it back to IDENTIFIER
pub(crate) fn identifier(p: &mut Parser<'_>) -> CompletedMarker {
let m = p.start();
p.bump(IDENT);
p.expect(IDENT);
m.complete(p, IDENTIFIER)
}

Expand Down
16 changes: 0 additions & 16 deletions crates/oq3_parser/src/grammar/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
match p.current() {
T![qubit] => qubit_declaration_stmt(p, m),
T![const] => expressions::classical_declaration_stmt(p, m),
IDENT if (la == IDENT || la == HARDWAREIDENT) => gate_call_stmt(p, m),
IDENT if (la == T![=] && p.nth(2) != T![=]) => assignment_statement_with_marker(p, m),
T![gate] => gate_definition(p, m),
T![break] => break_(p, m),
Expand All @@ -127,21 +126,6 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
Ok(())
}

// expressions::call_expr also handles some occurences of gate calls
// FIXME: params in parens are likely always caught in expressions::call_expr
fn gate_call_stmt(p: &mut Parser<'_>, m: Marker) {
// expressions::var_name(p);
expressions::atom::identifier(p); // name of gate
assert!(!p.at(T!['(']));
// This is never true, I hope
if p.at(T!['(']) {
expressions::call_arg_list(p);
}
params::arg_list_gate_call_qubits(p);
p.expect(SEMICOLON);
m.complete(p, GATE_CALL_STMT);
}

fn gphase_call(p: &mut Parser<'_>, m: Marker) {
assert!(p.at(T![gphase]));
p.bump(T![gphase]);
Expand Down
2 changes: 0 additions & 2 deletions crates/oq3_parser/src/grammar/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ fn _param_list_openqasm(p: &mut Parser<'_>, flavor: DefFlavor, m: Option<Marker>
let m = param_marker.take().unwrap_or_else(|| p.start());
if !(p.current().is_type_name() || p.at_ts(PARAM_FIRST)) {
p.error("expected value parameter");
println!("!!!! Got {:?}", p.current());
m.abandon(p);
break;
}
Expand All @@ -118,7 +117,6 @@ fn _param_list_openqasm(p: &mut Parser<'_>, flavor: DefFlavor, m: Option<Marker>
expressions::expr_or_range_expr(p);
true
}
// SetExpression => { m.abandon(p); expressions::expr(p); true }
GateCallQubits => arg_gate_call_qubit(p, m),
DefParams | DefCalParams => param_typed(p, m),
_ => param_untyped(p, m),
Expand Down
2 changes: 1 addition & 1 deletion crates/oq3_parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ impl Marker {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub(crate) struct CompletedMarker {
pos: u32,
kind: SyntaxKind,
Expand Down
Loading
Loading