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

add parser support for path related facts #190

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
9 changes: 9 additions & 0 deletions polonius-parser/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub struct Input {
pub blocks: Vec<Block>,
pub use_of_var_derefs_origin: Vec<(String, String)>,
pub drop_of_var_derefs_origin: Vec<(String, String)>,
pub child_path: Vec<(String, String)>,
pub path_is_var: Vec<(String, String)>,
}

impl Input {
Expand All @@ -15,6 +17,8 @@ impl Input {
known_subsets: Vec<KnownSubset>,
use_of_var_derefs_origin: Vec<(String, String)>,
drop_of_var_derefs_origin: Vec<(String, String)>,
child_path: Vec<(String, String)>,
path_is_var: Vec<(String, String)>,
blocks: Vec<Block>,
) -> Input {
// set-up placeholders as origins with a placeholder loan of the same name
Expand All @@ -31,6 +35,8 @@ impl Input {
known_subsets,
use_of_var_derefs_origin,
drop_of_var_derefs_origin,
child_path,
path_is_var,
blocks,
}
}
Expand Down Expand Up @@ -67,6 +73,9 @@ pub enum Fact {
OriginLiveOnEntry { origin: String },
DefineVariable { variable: String },
UseVariable { variable: String },
PathMovedAtBase { path: String },
PathAssignedAtBase { path: String },
PathAccessedAtBase { path: String },
}

#[derive(Debug, PartialEq)]
Expand Down
20 changes: 19 additions & 1 deletion polonius-parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl<'input> Lexer<'input> {
[b'{', ..] => (1, T!['{']),
[b'}', ..] => (1, T!['}']),
// parameters
[c @ b'\'' | c @ b'B' | c @ b'L' | c @ b'V', ..] => (
[c @ b'\'' | c @ b'B' | c @ b'L' | c @ b'V' | c @ b'P', ..] => (
input
.char_indices()
.skip(1)
Expand All @@ -67,6 +67,7 @@ impl<'input> Lexer<'input> {
b'B' => T![Block],
b'L' => T![loan],
b'V' => T![variable],
b'P' => T![path],
_ => unreachable!(),
},
),
Expand Down Expand Up @@ -95,6 +96,12 @@ impl<'input> Lexer<'input> {
kw if kw.starts_with("known_subsets".as_bytes()) => {
("known_subsets".len() as u32, T![known subsets])
}
kw if kw.starts_with("child_path".as_bytes()) => {
("child_path".len() as u32, T![child_path])
}
kw if kw.starts_with("path_is_var".as_bytes()) => {
("path_is_var".len() as u32, T![path_is_var])
}
// CFG keywords
kw if kw.starts_with("block".as_bytes()) => ("block".len() as u32, T![block]),
kw if kw.starts_with("goto".as_bytes()) => ("goto".len() as u32, T![goto]),
Expand Down Expand Up @@ -122,6 +129,17 @@ impl<'input> Lexer<'input> {
kw if kw.starts_with("var_dropped_at".as_bytes()) => {
("var_dropped_at".len() as u32, T![var_dropped_at])
}
kw if kw.starts_with("path_moved_at_base".as_bytes()) => {
("path_moved_at_base".len() as u32, T![path_moved_at_base])
}
kw if kw.starts_with("path_assigned_at_base".as_bytes()) => (
"path_assigned_at_base".len() as u32,
T![path_assigned_at_base],
),
kw if kw.starts_with("path_accessed_at_base".as_bytes()) => (
"path_accessed_at_base".len() as u32,
T![path_accessed_at_base],
),
// effect keywords - use
kw if kw.starts_with("use".as_bytes()) => ("use".len() as u32, T![use]),
_ => return None,
Expand Down
74 changes: 74 additions & 0 deletions polonius-parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@ where
let known_subsets = self.parse_known_subsets().unwrap_or_default();
let use_of_var_derefs_origin = self.parse_use_of_var_derefs_origin().unwrap_or_default();
let drop_of_var_derefs_origin = self.parse_drop_of_var_derefs_origin().unwrap_or_default();
let child_path = self.parse_child_path().unwrap_or_default();
let path_is_var = self.parse_path_is_var().unwrap_or_default();
let blocks = self.parse_blocks()?;
Ok(Input::new(
placeholders,
known_subsets,
use_of_var_derefs_origin,
drop_of_var_derefs_origin,
child_path,
path_is_var,
blocks,
))
}
Expand Down Expand Up @@ -164,6 +168,52 @@ where
Ok(var_region_mappings)
}

pub fn parse_child_path(&mut self) -> Result<Vec<(String, String)>> {
self.consume(T![child_path])?;
self.consume(T!['{'])?;
let path_path_mappings = self.parse_path_path_mappings()?;
self.consume(T!['}'])?;
Ok(path_path_mappings)
}

pub fn parse_path_path_mappings(&mut self) -> Result<Vec<(String, String)>> {
let mut path_var_mappings = Vec::new();
while self.try_consume(T!['(']) {
let child = self.parse_parameter(T![path])?;
self.consume(T![,])?;
let parent = self.parse_parameter(T![path])?;
self.consume(T![')'])?;
path_var_mappings.push((child, parent));
if !self.try_consume(T![,]) {
break;
}
}
Ok(path_var_mappings)
}

pub fn parse_path_is_var(&mut self) -> Result<Vec<(String, String)>> {
self.consume(T![path_is_var])?;
self.consume(T!['{'])?;
let path_var_mappings = self.parse_path_var_mappings()?;
self.consume(T!['}'])?;
Ok(path_var_mappings)
}

pub fn parse_path_var_mappings(&mut self) -> Result<Vec<(String, String)>> {
let mut path_var_mappings = Vec::new();
while self.try_consume(T!['(']) {
let path = self.parse_parameter(T![path])?;
self.consume(T![,])?;
let variable = self.parse_parameter(T![variable])?;
self.consume(T![')'])?;
path_var_mappings.push((path, variable));
if !self.try_consume(T![,]) {
break;
}
}
Ok(path_var_mappings)
}

pub fn parse_blocks(&mut self) -> Result<Vec<Block>> {
let mut blocks = Vec::new();
while self.try_consume(T![block]) {
Expand Down Expand Up @@ -293,6 +343,27 @@ where
self.consume(T![')'])?;
Ok(Fact::UseVariable { variable })
}
T![path_moved_at_base] => {
self.consume(T![path_moved_at_base])?;
self.consume(T!['('])?;
let path = self.parse_parameter(T![path])?;
self.consume(T![')'])?;
Ok(Fact::PathMovedAtBase { path })
}
T![path_assigned_at_base] => {
self.consume(T![path_assigned_at_base])?;
self.consume(T!['('])?;
let path = self.parse_parameter(T![path])?;
self.consume(T![')'])?;
Ok(Fact::PathAssignedAtBase { path })
}
T![path_accessed_at_base] => {
self.consume(T![path_accessed_at_base])?;
self.consume(T!['('])?;
let path = self.parse_parameter(T![path])?;
self.consume(T![')'])?;
Ok(Fact::PathAccessedAtBase { path })
}
found => Err(ParseError::UnexpectedToken {
found,
expected: vec![
Expand All @@ -304,6 +375,9 @@ where
T![var_defined_at],
T![origin_live_on_entry],
T![var_dropped_at],
T![path_moved_at_base],
T![path_assigned_at_base],
T![path_accessed_at_base],
],
position: self.position(),
}),
Expand Down
72 changes: 72 additions & 0 deletions polonius-parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,75 @@ fn known_subsets() {
]
);
}

#[test]
fn path_effects() {
let program = r"
placeholders {}

block B0 {
path_moved_at_base(P1);
path_assigned_at_base(P2);
path_accessed_at_base(P3);
}
";
let input = parse_input(program).expect("Path Effects");
let block = &input.blocks[0];
assert_eq!(block.statements.len(), 3);

let statement = &block.statements[0];
assert_eq!(
statement.effects,
[Effect::Fact(Fact::PathMovedAtBase {
path: "P1".to_string()
})]
);

let statement = &block.statements[1];
assert_eq!(
statement.effects,
[Effect::Fact(Fact::PathAssignedAtBase {
path: "P2".to_string()
})]
);

let statement = &block.statements[2];
assert_eq!(
statement.effects,
[Effect::Fact(Fact::PathAccessedAtBase {
path: "P3".to_string()
})]
);
}

#[test]
fn child_path() {
let program = r"
placeholders {}
child_path {(P1, P2), (P2, P3)}
";
let input = parse_input(program).expect("Child Path");
assert_eq!(
input.child_path,
[
("P1".to_string(), "P2".to_string()),
("P2".to_string(), "P3".to_string())
]
);
}

#[test]
fn path_is_var() {
let program = r"
placeholders {}
path_is_var {(P1, V1), (P2, V2)}
";
let input = parse_input(program).expect("Path is Var");
assert_eq!(
input.path_is_var,
[
("P1".to_string(), "V1".to_string()),
("P2".to_string(), "V2".to_string())
]
);
}
18 changes: 18 additions & 0 deletions polonius-parser/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum TokenKind {
KwDropOfVarDerefsOrigin,
KwPlaceholders,
KwKnownSubsets,
KwChildPath,
KwPathIsVar,
// CFG keywords
KwBlock,
KwGoto,
Expand All @@ -47,13 +49,17 @@ pub enum TokenKind {
KwVarDefinedAt,
KwOriginLiveOnEntry,
KwVarDroppedAt,
KwPathMovedAtBase,
KwPathAssignedAtBase,
KwPathAccesssedAtBase,
// effect keywords - use
KwUse,
// parameters
Origin,
Block,
Loan,
Variable,
Path,
Comment,
Whitespace,
Error,
Expand Down Expand Up @@ -102,6 +108,8 @@ macro_rules! T {
[drop_of_var_derefs_origin] => { $crate::token::TokenKind::KwDropOfVarDerefsOrigin};
[placeholders] => { $crate::token::TokenKind::KwPlaceholders};
[known subsets] => { $crate::token::TokenKind::KwKnownSubsets};
[child_path] => { $crate::token::TokenKind::KwChildPath};
[path_is_var] => { $crate::token::TokenKind::KwPathIsVar};
// CFG keywords
[block] => { $crate::token::TokenKind::KwBlock};
[goto] => { $crate::token::TokenKind::KwGoto};
Expand All @@ -114,13 +122,17 @@ macro_rules! T {
[var_defined_at] => { $crate::token::TokenKind::KwVarDefinedAt};
[origin_live_on_entry] => { $crate::token::TokenKind::KwOriginLiveOnEntry};
[var_dropped_at] => { $crate::token::TokenKind::KwVarDroppedAt};
[path_moved_at_base] => { $crate::token::TokenKind::KwPathMovedAtBase};
[path_assigned_at_base] => { $crate::token::TokenKind::KwPathAssignedAtBase};
[path_accessed_at_base] => { $crate::token::TokenKind::KwPathAccesssedAtBase};
// effect keywords - use
[use] => { $crate::token::TokenKind::KwUse};
// parameters
[origin] => { $crate::token::TokenKind::Origin};
[Block] => { $crate::token::TokenKind::Block};
[loan] => { $crate::token::TokenKind::Loan};
[variable] => { $crate::token::TokenKind::Variable};
[path] => { $crate::token::TokenKind::Path };
[comment] => { $crate::token::TokenKind::Comment};
[ws] => { $crate::token::TokenKind::Whitespace};
[error] => { $crate::token::TokenKind::Error};
Expand Down Expand Up @@ -158,6 +170,8 @@ impl fmt::Display for TokenKind {
T![drop_of_var_derefs_origin] => write!(f, "drop_of_var_derefs_origin"),
T![placeholders] => write!(f, "placeholders"),
T![known subsets] => write!(f, "known_subsets"),
T![child_path] => write!(f, "child_path"),
T![path_is_var] => write!(f, "path_is_var"),
T![block] => write!(f, "block"),
T![goto] => write!(f, "goto"),
T![outlives] => write!(f, "outlives"),
Expand All @@ -168,11 +182,15 @@ impl fmt::Display for TokenKind {
T![var_defined_at] => write!(f, "var_defined_at"),
T![origin_live_on_entry] => write!(f, "origin_live_on_entry"),
T![var_dropped_at] => write!(f, "var_dropped_at"),
T![path_moved_at_base] => write!(f, "path_moved_at_base"),
T![path_assigned_at_base] => write!(f, "path_assigned_at_base"),
T![path_accessed_at_base] => write!(f, "path_accessed_at_base"),
T![use] => write!(f, "use"),
T![origin] => write!(f, "Origin"),
T![Block] => write!(f, "Block"),
T![loan] => write!(f, "Loan"),
T![variable] => write!(f, "Variable"),
T![path] => write!(f, "Path"),
T![comment] => write!(f, "// Comment"),
T![ws] => write!(f, "<ws>"),
T![error] => write!(f, "<?>"),
Expand Down
32 changes: 31 additions & 1 deletion src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ pub(crate) fn parse_from_program(
}),
);

facts.child_path.extend(
input.child_path.iter().map(|(ref child, ref parent)| {
(tables.paths.intern(child), tables.paths.intern(parent))
}),
);

facts
.path_is_var
.extend(input.path_is_var.iter().map(|(ref path, ref variable)| {
(tables.paths.intern(path), tables.variables.intern(variable))
}));

for block in &input.blocks {
let block_name = &block.name;

Expand Down Expand Up @@ -252,7 +264,25 @@ fn emit_fact(facts: &mut Facts, fact: &Fact, point: Point, tables: &mut Interner
facts.var_used_at.insert((variable, point));
}

_ => {}
// facts: path_moved_at_base(Path, Point)
Fact::PathMovedAtBase { ref path } => {
let path = tables.paths.intern(path);
facts.path_moved_at_base.insert((path, point));
}

// facts: path_assigned_at_base(Path, Point)
Fact::PathAssignedAtBase { ref path } => {
let path = tables.paths.intern(path);
facts.path_assigned_at_base.insert((path, point));
}

// facts: path_accessed_at_base(Path, Point)
Fact::PathAccessedAtBase { ref path } => {
let path = tables.paths.intern(path);
facts.path_accessed_at_base.insert((path, point));
}

Fact::OriginLiveOnEntry { origin: _ } => {}
};
}

Expand Down