Skip to content

Commit

Permalink
feat: Allow features to enable builtin statements (#4773)
Browse files Browse the repository at this point in the history
* feat: Allow features to enable builtin statements

* chore: make generate

* chore: cargo clippy
  • Loading branch information
Markus Westerlind authored Jun 23, 2022
1 parent f3e84dd commit 2314ab7
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 56 deletions.
6 changes: 3 additions & 3 deletions libflux/flux-core/src/semantic/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ mod tests {
if let Err(err) = ast::check::check(ast::walk::Node::TypeExpression(&typ_expr)) {
panic!("TypeExpression parsing failed for int. {:?}", err);
}
convert_polytype(&typ_expr)?
convert_polytype(&typ_expr, &Default::default())?
})])
.unwrap();
if want != types {
Expand All @@ -460,7 +460,7 @@ mod tests {
"TypeExpression parsing failed for int. {:?}", err
);
}
convert_polytype(&typ_expr, )?
convert_polytype(&typ_expr, &Default::default())?
},
String::from("b") => {
let mut p = parser::Parser::new("{x: int , y: int}");
Expand All @@ -470,7 +470,7 @@ mod tests {
"TypeExpression parsing failed for int. {:?}", err
);
}
convert_polytype(&typ_expr, )?
convert_polytype(&typ_expr, &Default::default())?
},
};
if want
Expand Down
2 changes: 1 addition & 1 deletion libflux/flux-core/src/semantic/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ mod tests {
ctr = ctr + 1;
}
let ast_pkg = merge_ast_files(ast_files);
let sem_pkg = convert::convert_package(&ast_pkg, &Default::default())?;
let sem_pkg = convert::convert_package(&ast_pkg, &Default::default(), &Default::default())?;
Ok(sem_pkg)
}

Expand Down
112 changes: 87 additions & 25 deletions libflux/flux-core/src/semantic/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
env::Environment,
nodes::*,
types::{self, BuiltinType, MonoType, MonoTypeMap, SemanticMap},
AnalyzerConfig, Feature,
},
};

Expand Down Expand Up @@ -71,8 +72,12 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
/// overhead involved.
///
/// [AST package]: ast::Package
pub fn convert_package(pkg: &ast::Package, env: &Environment) -> Result<Package, Errors<Error>> {
let mut converter = Converter::with_env(env);
pub fn convert_package(
pkg: &ast::Package,
env: &Environment,
config: &AnalyzerConfig,
) -> Result<Package, Errors<Error>> {
let mut converter = Converter::with_env(env, config);
let r = converter.convert_package(pkg);
converter.finish()?;
Ok(r)
Expand All @@ -84,8 +89,9 @@ pub fn convert_package(pkg: &ast::Package, env: &Environment) -> Result<Package,
/// [`PolyType`]: types::PolyType
pub fn convert_polytype(
type_expression: &ast::TypeExpression,
config: &AnalyzerConfig,
) -> Result<types::PolyType, Errors<Error>> {
let mut converter = Converter::new();
let mut converter = Converter::new(config);
let r = converter.convert_polytype(type_expression);
converter.finish()?;
Ok(r)
Expand All @@ -95,8 +101,9 @@ pub fn convert_polytype(
pub(crate) fn convert_monotype(
ty: &ast::MonoType,
tvars: &mut BTreeMap<String, types::BoundTvar>,
config: &AnalyzerConfig,
) -> Result<MonoType, Errors<Error>> {
let mut converter = Converter::new();
let mut converter = Converter::new(config);
let r = converter.convert_monotype(&ty, tvars);
converter.finish()?;
Ok(r)
Expand Down Expand Up @@ -257,6 +264,24 @@ pub struct SymbolInfo {
#[allow(missing_docs)]
pub type PackageInfo = HashMap<Symbol, SymbolInfo>;

fn get_attribute<'a>(comments: impl IntoIterator<Item = &'a str>, attr: &str) -> Option<&'a str> {
comments.into_iter().find_map(|comment| {
// Remove the comment and any preceding whitespace
let comment = comment.trim_start_matches("//").trim_start();
if let Some(content) = comment.strip_prefix('@') {
let mut iter = content.splitn(2, char::is_whitespace);
let name = iter.next().unwrap();
if name == attr {
Some(iter.next().unwrap_or("").trim())
} else {
None
}
} else {
None
}
})
}

#[derive(Debug, Default)]
struct Symbols<'a> {
symbols: SymbolStack,
Expand All @@ -266,9 +291,9 @@ struct Symbols<'a> {
}

impl<'a> Symbols<'a> {
fn with_env(env: &'a Environment) -> Self {
fn new(env: Option<&'a Environment>) -> Self {
Symbols {
env: Some(env),
env,
package_info: Default::default(),
local_labels: Default::default(),
symbols: SymbolStack::default(),
Expand All @@ -287,6 +312,7 @@ impl<'a> Symbols<'a> {
if package.is_none() && !self.local_labels.contains_key(&symbol[..]) {
self.local_labels.insert(symbol.to_string(), symbol.clone());
}

symbol
}

Expand Down Expand Up @@ -326,20 +352,23 @@ impl<'a> Symbols<'a> {
pub(crate) struct Converter<'a> {
symbols: Symbols<'a>,
errors: Errors<Error>,
config: &'a AnalyzerConfig,
}

impl<'a> Converter<'a> {
fn new() -> Self {
fn new(config: &'a AnalyzerConfig) -> Self {
Converter {
symbols: Symbols::default(),
symbols: Symbols::new(None),
errors: Errors::new(),
config,
}
}

pub(crate) fn with_env(env: &'a Environment) -> Self {
pub(crate) fn with_env(env: &'a Environment, config: &'a AnalyzerConfig) -> Self {
Converter {
symbols: Symbols::with_env(env),
symbols: Symbols::new(Some(env)),
errors: Errors::new(),
config,
}
}

Expand Down Expand Up @@ -385,7 +414,7 @@ impl<'a> Converter<'a> {
let body = file
.body
.iter()
.map(|s| self.convert_statement(package_name, s))
.filter_map(|s| self.convert_statement(package_name, s))
.collect::<Vec<Statement>>();

File {
Expand Down Expand Up @@ -430,13 +459,13 @@ impl<'a> Converter<'a> {
}
}

fn convert_statement(&mut self, package: &str, stmt: &ast::Statement) -> Statement {
match stmt {
fn convert_statement(&mut self, package: &str, stmt: &ast::Statement) -> Option<Statement> {
Some(match stmt {
ast::Statement::Option(s) => {
Statement::Option(Box::new(self.convert_option_statement(s)))
}
ast::Statement::Builtin(s) => {
Statement::Builtin(self.convert_builtin_statement(package, s))
Statement::Builtin(self.convert_builtin_statement(package, s)?)
}
ast::Statement::Test(s) => Statement::Test(Box::new(self.convert_test_statement(s))),
ast::Statement::TestCase(s) => {
Expand All @@ -454,7 +483,7 @@ impl<'a> Converter<'a> {
ast::Statement::Bad(s) => Statement::Error(BadStmt {
loc: s.base.location.clone(),
}),
}
})
}

fn convert_assignment(&mut self, assign: &ast::Assignment) -> Assignment {
Expand All @@ -473,12 +502,29 @@ impl<'a> Converter<'a> {
}
}

fn convert_builtin_statement(&mut self, package: &str, stmt: &ast::BuiltinStmt) -> BuiltinStmt {
BuiltinStmt {
fn convert_builtin_statement(
&mut self,
package: &str,
stmt: &ast::BuiltinStmt,
) -> Option<BuiltinStmt> {
// Only include builtin statements that have the `feature` attribute if a matching
// feature is detected
if let Some(attr) = get_attribute(
stmt.base.comments.iter().map(|c| c.text.as_str()),
"feature",
)
.and_then(|attr| attr.parse::<Feature>().ok())
{
if self.config.features.iter().all(|feature| *feature != attr) {
return None;
}
}

Some(BuiltinStmt {
loc: stmt.base.location.clone(),
id: self.define_identifier(Some(package), &stmt.id, &stmt.base.comments),
typ_expr: self.convert_polytype(&stmt.ty),
}
})
}
fn convert_testcase(&mut self, package: &str, stmt: &ast::TestCaseStmt) -> TestCaseStmt {
TestCaseStmt {
Expand All @@ -492,7 +538,7 @@ impl<'a> Converter<'a> {
.block
.body
.iter()
.map(|s| self.convert_statement(package, s))
.filter_map(|s| self.convert_statement(package, s))
.collect(),
}
}
Expand Down Expand Up @@ -1345,7 +1391,8 @@ mod tests {
}

fn test_convert(pkg: ast::Package) -> Result<Package, Errors<Error>> {
let mut converter = Converter::new();
let config = AnalyzerConfig::default();
let mut converter = Converter::new(&config);
let mut pkg = converter.convert_package(&pkg);
converter.finish()?;

Expand Down Expand Up @@ -2741,11 +2788,18 @@ mod tests {
test_convert(pkg).unwrap();
}

fn convert_monotype_test(
ty: &ast::MonoType,
tvars: &mut BTreeMap<String, types::BoundTvar>,
) -> Result<MonoType, Errors<Error>> {
convert_monotype(ty, tvars, &Default::default())
}

#[test]
fn test_convert_monotype_int() {
let monotype = Parser::new("int").parse_monotype();
let mut m = BTreeMap::new();
let got = convert_monotype(&monotype, &mut m).unwrap();
let got = convert_monotype_test(&monotype, &mut m).unwrap();
let want = MonoType::INT;
assert_eq!(want, got);
}
Expand All @@ -2755,7 +2809,7 @@ mod tests {
let monotype = Parser::new("{ A with b: int }").parse_monotype();

let mut m = BTreeMap::new();
let got = convert_monotype(&monotype, &mut m).unwrap();
let got = convert_monotype_test(&monotype, &mut m).unwrap();
let want = MonoType::from(types::Record::Extension {
head: types::Property {
k: types::RecordLabel::from("b"),
Expand All @@ -2771,7 +2825,7 @@ mod tests {
let monotype_ex = Parser::new("(?A: int) => int").parse_monotype();

let mut m = BTreeMap::new();
let got = convert_monotype(&monotype_ex, &mut m).unwrap();
let got = convert_monotype_test(&monotype_ex, &mut m).unwrap();
let mut opt = MonoTypeMap::new();
opt.insert(String::from("A"), MonoType::INT.into());
let want = MonoType::from(types::Function {
Expand All @@ -2787,7 +2841,7 @@ mod tests {
fn test_convert_polytype() {
let type_exp =
Parser::new("(A: T, B: S) => T where T: Addable, S: Divisible").parse_type_expression();
let got = convert_polytype(&type_exp).unwrap();
let got = convert_polytype(&type_exp, &Default::default()).unwrap();

let want = {
let mut vars = Vec::<types::BoundTvar>::new();
Expand Down Expand Up @@ -2820,7 +2874,7 @@ mod tests {
fn test_convert_polytype_2() {
let type_exp = Parser::new("(A: T, B: S) => T where T: Addable").parse_type_expression();

let got = convert_polytype(&type_exp).unwrap();
let got = convert_polytype(&type_exp, &Default::default()).unwrap();
let mut vars = Vec::<types::BoundTvar>::new();
vars.push(types::BoundTvar(0));
vars.push(types::BoundTvar(1));
Expand All @@ -2841,4 +2895,12 @@ mod tests {
let want = types::PolyType { vars, cons, expr };
assert_eq!(want, got);
}

#[test]
fn test_get_attribute() {
assert_eq!(
get_attribute(["// @feature labelPolymorphism\n"], "feature"),
Some("labelPolymorphism"),
);
}
}
2 changes: 1 addition & 1 deletion libflux/flux-core/src/semantic/flatbuffers/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ re !~ /foo/
package: String::from("test"),
files: f,
};
let mut pkg = match convert::convert_package(&pkg, &Default::default()) {
let mut pkg = match convert::convert_package(&pkg, &Default::default(), &Default::default()) {
Ok(pkg) => pkg,
Err(e) => {
assert!(false, "{}", e);
Expand Down
6 changes: 3 additions & 3 deletions libflux/flux-core/src/semantic/flatbuffers/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ mod tests {
if let Err(err) = ast::check::check(ast::walk::Node::TypeExpression(&typ_expr)) {
panic!("TypeExpression parsing failed for {}. {:?}", expr, err);
}
let want = convert_polytype(&typ_expr).unwrap();
let want = convert_polytype(&typ_expr, &Default::default()).unwrap();

let mut builder = flatbuffers::FlatBufferBuilder::new();
let buf = serialize(&mut builder, want.clone(), build_polytype);
Expand All @@ -746,14 +746,14 @@ mod tests {
if let Err(err) = ast::check::check(ast::walk::Node::TypeExpression(&typ_expr)) {
panic!("TypeExpression parsing failed for bool. {:?}", err);
}
let a = convert_polytype(&typ_expr).unwrap();
let a = convert_polytype(&typ_expr, &Default::default()).unwrap();

let mut p = parser::Parser::new("time");
let typ_expr = p.parse_type_expression();
if let Err(err) = ast::check::check(ast::walk::Node::TypeExpression(&typ_expr)) {
panic!("TypeExpression parsing failed for time. {:?}", err);
}
let b = convert_polytype(&typ_expr).unwrap();
let b = convert_polytype(&typ_expr, &Default::default()).unwrap();

let want: PackageExports = vec![
(Symbol::from("a"), a.clone()),
Expand Down
2 changes: 1 addition & 1 deletion libflux/flux-core/src/semantic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ impl<'env, I: import::Importer> Analyzer<'env, I> {
}

let (mut sem_pkg, package_info) = {
let mut converter = convert::Converter::with_env(&self.env);
let mut converter = convert::Converter::with_env(&self.env, &self.config);
let sem_pkg = converter.convert_package(ast_pkg);

let package_info = converter.take_package_info();
Expand Down
Loading

0 comments on commit 2314ab7

Please sign in to comment.