mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-01-09 14:48:16 -05:00
Error handling in Statement processor (#2375)
This commit is contained in:
@@ -834,8 +834,8 @@ impl AnalysisASMFile {
|
||||
|
||||
pub fn get_machine(&self, ty: &AbsoluteSymbolPath) -> Option<&Machine> {
|
||||
let mut path = ty.clone();
|
||||
let name = path.pop().unwrap();
|
||||
self.modules[&path].machines.get(&name)
|
||||
let name = path.pop()?;
|
||||
self.modules.get(&path)?.machines.get(&name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,13 @@ impl Error {
|
||||
pub fn source_ref(&self) -> &SourceRef {
|
||||
&self.source_ref
|
||||
}
|
||||
|
||||
pub fn extend_message<F>(&self, f: F) -> Error
|
||||
where
|
||||
F: FnOnce(&str) -> String,
|
||||
{
|
||||
self.source_ref().with_error(f(self.message()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_parse_error(
|
||||
|
||||
@@ -14,8 +14,8 @@ use powdr_ast::parsed::asm::{
|
||||
use powdr_ast::parsed::types::Type;
|
||||
use powdr_ast::parsed::visitor::{AllChildren, Children};
|
||||
use powdr_ast::parsed::{
|
||||
self, FunctionKind, LambdaExpression, PILFile, PilStatement, SymbolCategory,
|
||||
TraitImplementation, TypedExpression,
|
||||
self, Expression as ParsedExpression, FunctionKind, LambdaExpression, PILFile, PilStatement,
|
||||
SourceReference, SymbolCategory, TraitImplementation, TypedExpression,
|
||||
};
|
||||
use powdr_number::{FieldElement, GoldilocksField};
|
||||
|
||||
@@ -149,13 +149,20 @@ impl PILAnalyzer {
|
||||
files = once(core).chain(files).collect();
|
||||
}
|
||||
|
||||
let mut errors = Vec::new();
|
||||
for PILFile(file) in files {
|
||||
self.current_namespace = Default::default();
|
||||
for statement in file {
|
||||
self.handle_statement(statement);
|
||||
if let Err(e) = self.handle_statement(statement) {
|
||||
errors.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
if errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds core types if they are not present in the input.
|
||||
@@ -472,7 +479,7 @@ impl PILAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_statement(&mut self, statement: PilStatement) {
|
||||
fn handle_statement(&mut self, statement: PilStatement) -> Result<(), Error> {
|
||||
match statement {
|
||||
PilStatement::Include(_, _) => unreachable!(),
|
||||
PilStatement::Namespace(_, name, degree) => self.handle_namespace(name, degree),
|
||||
@@ -481,7 +488,7 @@ impl PILAnalyzer {
|
||||
let mut counters = self.symbol_counters.take().unwrap();
|
||||
let items =
|
||||
StatementProcessor::new(self.driver(), &mut counters, self.polynomial_degree)
|
||||
.handle_statement(statement);
|
||||
.handle_statement(statement)?;
|
||||
self.symbol_counters = Some(counters);
|
||||
for item in items {
|
||||
match item {
|
||||
@@ -519,41 +526,49 @@ impl PILAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_namespace(&mut self, name: SymbolPath, degree: Option<parsed::NamespaceDegree>) {
|
||||
let evaluate_degree_bound = |e| {
|
||||
let e = match ExpressionProcessor::new(self.driver(), &Default::default())
|
||||
fn handle_namespace(
|
||||
&mut self,
|
||||
name: SymbolPath,
|
||||
degree: Option<parsed::NamespaceDegree>,
|
||||
) -> Result<(), Error> {
|
||||
let evaluate_degree_bound = |e: ParsedExpression| -> Result<u64, Error> {
|
||||
let source = e.source_reference().clone();
|
||||
let e = ExpressionProcessor::new(self.driver(), &Default::default())
|
||||
.process_expression(e)
|
||||
{
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
// TODO propagate this error up
|
||||
panic!("Failed to evaluate degree bound: {e}");
|
||||
}
|
||||
};
|
||||
u64::try_from(
|
||||
evaluator::evaluate_expression::<GoldilocksField>(
|
||||
&e,
|
||||
&self.definitions,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.try_to_integer()
|
||||
.unwrap(),
|
||||
.map_err(|err| {
|
||||
err.extend_message(|m| format!("Failed to evaluate degree bound: {m}"))
|
||||
})?;
|
||||
|
||||
let value = evaluator::evaluate_expression::<GoldilocksField>(
|
||||
&e,
|
||||
&self.definitions,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
.try_to_integer()
|
||||
.map_err(|err| source.with_error(err.to_string()))?;
|
||||
|
||||
u64::try_from(value)
|
||||
.map_err(|_| source.with_error("Degree bound too large".to_string()))
|
||||
};
|
||||
|
||||
self.polynomial_degree = degree.map(|degree| DegreeRange {
|
||||
min: evaluate_degree_bound(degree.min),
|
||||
max: evaluate_degree_bound(degree.max),
|
||||
});
|
||||
self.current_namespace = AbsoluteSymbolPath::default().join(name);
|
||||
}
|
||||
self.polynomial_degree = degree
|
||||
.map(|degree| -> Result<_, Error> {
|
||||
Ok(DegreeRange {
|
||||
min: evaluate_degree_bound(degree.min)?,
|
||||
max: evaluate_degree_bound(degree.max)?,
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
self.current_namespace = AbsoluteSymbolPath::default().join(name);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn driver(&self) -> Driver {
|
||||
Driver(self)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use powdr_ast::parsed::{
|
||||
ArrayExpression, NamedExpression, StructDeclaration, SymbolCategory, TraitImplementation,
|
||||
TypeDeclaration,
|
||||
};
|
||||
use powdr_parser_util::SourceRef;
|
||||
use powdr_parser_util::{Error, SourceRef};
|
||||
use std::str::FromStr;
|
||||
|
||||
use powdr_ast::analyzed::{
|
||||
@@ -121,7 +121,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_statement(&mut self, statement: PilStatement) -> Vec<PILItem> {
|
||||
pub fn handle_statement(&mut self, statement: PilStatement) -> Result<Vec<PILItem>, Error> {
|
||||
match statement {
|
||||
PilStatement::Include(_, _) => {
|
||||
panic!("Includes must be handled outside the statement processor.")
|
||||
@@ -130,7 +130,7 @@ where
|
||||
panic!("Namespaces must be handled outside the statement processor.")
|
||||
}
|
||||
PilStatement::PolynomialDefinition(source, name, value) => {
|
||||
let (name, ty) = self.name_and_type_from_polynomial_name(name, Type::Inter);
|
||||
let (name, ty) = self.name_and_type_from_polynomial_name(name, Type::Inter)?;
|
||||
self.handle_symbol_definition(
|
||||
source,
|
||||
name,
|
||||
@@ -163,7 +163,7 @@ where
|
||||
) => {
|
||||
assert!(polynomials.len() == 1);
|
||||
let (name, ty) =
|
||||
self.name_and_type_from_polynomial_name(polynomials.pop().unwrap(), Type::Col);
|
||||
self.name_and_type_from_polynomial_name(polynomials.pop().unwrap(), Type::Col)?;
|
||||
|
||||
self.handle_symbol_definition(
|
||||
source,
|
||||
@@ -197,15 +197,16 @@ where
|
||||
Some(FunctionDefinition::TraitDeclaration(trait_decl.clone())),
|
||||
),
|
||||
PilStatement::TraitImplementation(_, trait_impl) => {
|
||||
let trait_impl = self.process_trait_implementation(trait_impl);
|
||||
vec![PILItem::TraitImplementation(trait_impl)]
|
||||
let trait_impl = self.process_trait_implementation(trait_impl)?;
|
||||
Ok(vec![PILItem::TraitImplementation(trait_impl)])
|
||||
}
|
||||
PilStatement::Expression(_, expr) => {
|
||||
let new_expr = self
|
||||
.expression_processor(&Default::default())
|
||||
.process_expression(expr)?;
|
||||
|
||||
Ok(vec![PILItem::ProofItem(new_expr)])
|
||||
}
|
||||
PilStatement::Expression(_, expr) => vec![PILItem::ProofItem(
|
||||
self.expression_processor(&Default::default())
|
||||
.process_expression(expr)
|
||||
// TODO propagate this error up
|
||||
.expect("Expression processing failed"),
|
||||
)],
|
||||
PilStatement::StructDeclaration(source, struct_declaration) => self
|
||||
.handle_symbol_definition(
|
||||
source,
|
||||
@@ -224,15 +225,16 @@ where
|
||||
&mut self,
|
||||
PolynomialName { name, array_size }: PolynomialName,
|
||||
base_type: Type,
|
||||
) -> (String, Option<TypeScheme>) {
|
||||
) -> Result<(String, Option<TypeScheme>), Error> {
|
||||
let ty = Some(match array_size {
|
||||
None => base_type.into(),
|
||||
Some(len) => {
|
||||
let len = self
|
||||
.expression_processor(&Default::default())
|
||||
.process_expression(len)
|
||||
// TODO propagate this error up
|
||||
.expect("Failed to process length expression");
|
||||
.map_err(|err| {
|
||||
err.extend_message(|m| format!("Failed to process length expression: {m}"))
|
||||
})?;
|
||||
let length = untyped_evaluator::evaluate_expression_to_int(self.driver, len)
|
||||
.map(|length| {
|
||||
length
|
||||
@@ -250,7 +252,7 @@ where
|
||||
.into()
|
||||
}
|
||||
});
|
||||
(name, ty)
|
||||
Ok((name, ty))
|
||||
}
|
||||
|
||||
fn handle_generic_definition(
|
||||
@@ -259,7 +261,7 @@ where
|
||||
name: String,
|
||||
type_scheme: Option<TypeScheme<parsed::Expression>>,
|
||||
value: Option<parsed::Expression>,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let type_scheme = type_scheme.map(|ts| {
|
||||
let vars = ts.vars;
|
||||
let duplicates = vars.vars().duplicates().collect::<Vec<_>>();
|
||||
@@ -355,11 +357,11 @@ where
|
||||
source: SourceRef,
|
||||
stage: Option<u32>,
|
||||
polynomials: Vec<PolynomialName>,
|
||||
) -> Vec<PILItem> {
|
||||
polynomials
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let result = polynomials
|
||||
.into_iter()
|
||||
.flat_map(|poly_name| {
|
||||
let (name, ty) = self.name_and_type_from_polynomial_name(poly_name, Type::Col);
|
||||
.map(|poly_name| {
|
||||
let (name, ty) = self.name_and_type_from_polynomial_name(poly_name, Type::Col)?;
|
||||
self.handle_symbol_definition(
|
||||
source.clone(),
|
||||
name,
|
||||
@@ -369,7 +371,12 @@ where
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn handle_symbol_definition(
|
||||
@@ -380,7 +387,7 @@ where
|
||||
stage: Option<u32>,
|
||||
type_scheme: Option<TypeScheme>,
|
||||
value: Option<FunctionDefinition>,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let length = type_scheme.as_ref().and_then(|t| {
|
||||
if symbol_kind == SymbolKind::Other() {
|
||||
None
|
||||
@@ -424,7 +431,7 @@ where
|
||||
Some(FunctionDefinition::Array(value)) => {
|
||||
self.process_array_symbol(symbol, type_scheme, value)
|
||||
}
|
||||
None => vec![PILItem::Definition(symbol, None)],
|
||||
None => Ok(vec![PILItem::Definition(symbol, None)]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +441,7 @@ where
|
||||
symbol: Symbol,
|
||||
type_scheme: Option<TypeScheme>,
|
||||
expr: parsed::Expression,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
if symbol_kind == SymbolKind::Poly(PolynomialType::Committed) {
|
||||
// The only allowed value for a witness column is a query function.
|
||||
assert!(matches!(
|
||||
@@ -456,12 +463,11 @@ where
|
||||
let value = FunctionValueDefinition::Expression(TypedExpression {
|
||||
e: self
|
||||
.expression_processor(&type_vars)
|
||||
.process_expression(expr)
|
||||
.expect("Failed to process expression"),
|
||||
.process_expression(expr)?,
|
||||
type_scheme,
|
||||
});
|
||||
|
||||
vec![PILItem::Definition(symbol, Some(value))]
|
||||
Ok(vec![PILItem::Definition(symbol, Some(value))])
|
||||
}
|
||||
|
||||
fn process_array_symbol(
|
||||
@@ -469,15 +475,14 @@ where
|
||||
symbol: Symbol,
|
||||
type_scheme: Option<TypeScheme>,
|
||||
value: ArrayExpression,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let expression = self
|
||||
.expression_processor(&Default::default())
|
||||
.process_array_expression(value)
|
||||
.expect("Failed to process array expression");
|
||||
.process_array_expression(value)?;
|
||||
assert!(type_scheme.is_none() || type_scheme == Some(Type::Col.into()));
|
||||
let value = FunctionValueDefinition::Array(expression);
|
||||
|
||||
vec![PILItem::Definition(symbol, Some(value))]
|
||||
Ok(vec![PILItem::Definition(symbol, Some(value))])
|
||||
}
|
||||
|
||||
/// Given a list of (absolute_name, value) pairs, create PIL items for each of them.
|
||||
@@ -510,32 +515,30 @@ where
|
||||
poly: parsed::NamespacedPolynomialReference,
|
||||
array_index: Option<parsed::Expression>,
|
||||
index: parsed::Expression,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let id = self.counters.dispense_public_id();
|
||||
let name = self.driver.resolve_decl(&name);
|
||||
let polynomial = self
|
||||
.expression_processor(&Default::default())
|
||||
.process_namespaced_polynomial_reference(poly)
|
||||
.expect("Failed to process polynomial reference");
|
||||
.map_err(|err| source.with_error(err))?;
|
||||
let type_vars = Default::default();
|
||||
let mut expression_processor = self.expression_processor(&type_vars);
|
||||
let array_index = array_index.map(|i| {
|
||||
let i = expression_processor
|
||||
.process_expression(i)
|
||||
// TODO propagate this error up
|
||||
.expect("Failed to process array index expression");
|
||||
let index: u64 = untyped_evaluator::evaluate_expression_to_int(self.driver, i)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
assert!(index <= usize::MAX as u64);
|
||||
index as usize
|
||||
});
|
||||
|
||||
let index = expression_processor
|
||||
.process_expression(index) // TODO propagate this error up
|
||||
.expect("Failed to process index");
|
||||
vec![PILItem::PublicDeclaration(PublicDeclaration {
|
||||
let array_index = array_index
|
||||
.map(|i| {
|
||||
let i = expression_processor.process_expression(i).map_err(|err| {
|
||||
err.extend_message(|m| format!("Failed to process array index: {m}"))
|
||||
})?;
|
||||
let index: u64 = untyped_evaluator::evaluate_expression_to_int(self.driver, i)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
assert!(index <= usize::MAX as u64);
|
||||
Ok(index as usize)
|
||||
})
|
||||
.transpose()?;
|
||||
let index = expression_processor.process_expression(index)?;
|
||||
Ok(vec![PILItem::PublicDeclaration(PublicDeclaration {
|
||||
id,
|
||||
source,
|
||||
name: name.to_string(),
|
||||
@@ -545,7 +548,7 @@ where
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
})]
|
||||
})])
|
||||
}
|
||||
|
||||
fn expression_processor<'b>(
|
||||
@@ -565,7 +568,7 @@ where
|
||||
name: String,
|
||||
symbol: Symbol,
|
||||
enum_decl: EnumDeclaration<parsed::Expression>,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let type_vars = enum_decl.type_vars.vars().collect();
|
||||
let variants = enum_decl
|
||||
.variants
|
||||
@@ -596,14 +599,14 @@ where
|
||||
.collect();
|
||||
let var_items = self.process_inner_definitions(source, inner_items);
|
||||
|
||||
iter::once(PILItem::Definition(
|
||||
Ok(iter::once(PILItem::Definition(
|
||||
symbol,
|
||||
Some(FunctionValueDefinition::TypeDeclaration(
|
||||
TypeDeclaration::Enum(enum_decl.clone()),
|
||||
)),
|
||||
))
|
||||
.chain(var_items)
|
||||
.collect()
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn process_enum_variant(
|
||||
@@ -625,7 +628,7 @@ where
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
struct_decl: StructDeclaration<parsed::Expression>,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let StructDeclaration {
|
||||
name,
|
||||
type_vars,
|
||||
@@ -647,13 +650,13 @@ where
|
||||
fields,
|
||||
};
|
||||
|
||||
iter::once(PILItem::Definition(
|
||||
Ok(iter::once(PILItem::Definition(
|
||||
symbol,
|
||||
Some(FunctionValueDefinition::TypeDeclaration(
|
||||
TypeDeclaration::Struct(struct_decl),
|
||||
)),
|
||||
))
|
||||
.collect()
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn process_trait_declaration(
|
||||
@@ -662,7 +665,7 @@ where
|
||||
name: String,
|
||||
symbol: Symbol,
|
||||
trait_decl: TraitDeclaration<parsed::Expression>,
|
||||
) -> Vec<PILItem> {
|
||||
) -> Result<Vec<PILItem>, Error> {
|
||||
let type_vars = trait_decl.type_vars.iter().collect();
|
||||
let functions = trait_decl
|
||||
.functions
|
||||
@@ -696,20 +699,20 @@ where
|
||||
.collect();
|
||||
let trait_functions = self.process_inner_definitions(source, inner_items);
|
||||
|
||||
iter::once(PILItem::Definition(
|
||||
Ok(iter::once(PILItem::Definition(
|
||||
symbol,
|
||||
Some(FunctionValueDefinition::TraitDeclaration(
|
||||
trait_decl.clone(),
|
||||
)),
|
||||
))
|
||||
.chain(trait_functions)
|
||||
.collect()
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn process_trait_implementation(
|
||||
&self,
|
||||
trait_impl: parsed::TraitImplementation<parsed::Expression>,
|
||||
) -> TraitImplementation<Expression> {
|
||||
) -> Result<TraitImplementation<Expression>, Error> {
|
||||
let type_vars: HashSet<_> = trait_impl.type_scheme.vars.vars().collect();
|
||||
if !type_vars.is_empty() {
|
||||
unimplemented!("Generic impls are not supported yet.");
|
||||
@@ -717,15 +720,17 @@ where
|
||||
let functions = trait_impl
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|named| NamedExpression {
|
||||
name: named.name,
|
||||
body: Arc::new(
|
||||
self.expression_processor(&type_vars)
|
||||
.process_expression(Arc::try_unwrap(named.body).unwrap())
|
||||
.expect("Failed to process expression inside trait"),
|
||||
),
|
||||
.map(|named| {
|
||||
let processed_expr = self
|
||||
.expression_processor(&type_vars)
|
||||
.process_expression(Arc::try_unwrap(named.body).unwrap())?;
|
||||
|
||||
Ok(NamedExpression {
|
||||
name: named.name,
|
||||
body: Arc::new(processed_expr),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<Vec<NamedExpression<Arc<Expression>>>, Error>>()?;
|
||||
|
||||
let Type::Tuple(TupleType { items }) = trait_impl.type_scheme.ty.clone() else {
|
||||
panic!("Type from trait scheme is not a tuple.")
|
||||
@@ -743,11 +748,15 @@ where
|
||||
&self
|
||||
.driver
|
||||
.resolve_ref(&trait_impl.name, SymbolCategory::TraitDeclaration)
|
||||
.expect("TODO: Handle this up in the code"),
|
||||
.map_err(|err| {
|
||||
trait_impl
|
||||
.source_ref
|
||||
.with_error(format!("Cannot find trait {}: {}", trait_impl.name, err))
|
||||
})?,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
TraitImplementation {
|
||||
Ok(TraitImplementation {
|
||||
name,
|
||||
source_ref: trait_impl.source_ref,
|
||||
type_scheme: TypeScheme {
|
||||
@@ -757,6 +766,6 @@ where
|
||||
}),
|
||||
},
|
||||
functions,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user