1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00
This commit is contained in:
dark64 2022-02-08 12:45:04 +01:00
parent cf538e5273
commit 54ebeefdf9
5 changed files with 100 additions and 24 deletions

View file

@ -253,6 +253,7 @@ impl<'ast> From<pest::Parameter<'ast>> for absy::ParameterNode<'ast> {
fn statements_from_statement(statement: pest::Statement) -> Vec<absy::StatementNode> {
match statement {
pest::Statement::Definition(s) => statements_from_definition(s),
pest::Statement::Let(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Iteration(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Assertion(s) => vec![absy::StatementNode::from(s)],
pest::Statement::Return(s) => vec![absy::StatementNode::from(s)],
@ -351,6 +352,15 @@ fn statements_from_definition(definition: pest::DefinitionStatement) -> Vec<absy
}
}
impl<'ast> From<pest::LetStatement<'ast>> for absy::StatementNode<'ast> {
fn from(statement: pest::LetStatement<'ast>) -> absy::StatementNode<'ast> {
use crate::absy::NodeValue;
absy::Statement::Let(statement.id.span.as_str(), statement.expression.into())
.span(statement.span)
}
}
impl<'ast> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast> {
fn from(statement: pest::ReturnStatement<'ast>) -> absy::StatementNode<'ast> {
use crate::absy::NodeValue;

View file

@ -383,6 +383,7 @@ impl<'ast> fmt::Display for Assignee<'ast> {
#[derive(Debug, Clone, PartialEq)]
pub enum Statement<'ast> {
Return(ExpressionListNode<'ast>),
Let(Identifier<'ast>, ExpressionNode<'ast>),
Declaration(VariableNode<'ast>),
Definition(AssigneeNode<'ast>, ExpressionNode<'ast>),
Assertion(ExpressionNode<'ast>, Option<String>),
@ -402,6 +403,7 @@ impl<'ast> fmt::Display for Statement<'ast> {
match *self {
Statement::Return(ref expr) => write!(f, "return {}", expr),
Statement::Declaration(ref var) => write!(f, "{}", var),
Statement::Let(ref id, ref e) => write!(f, "let {} = {}", id, e),
Statement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
Statement::Assertion(ref e, ref message) => {
write!(f, "assert({}", e)?;

View file

@ -1171,8 +1171,8 @@ impl<'ast, T: Field> Checker<'ast, T> {
}
match self.check_statement(stat, module_id, &state.types) {
Ok(statement) => {
if let TypedStatement::Return(e) = &statement {
Ok(mut statements) => {
if let TypedStatement::Return(e) = &statements[0] {
match e.iter().map(|e| e.get_type()).collect::<Vec<_>>()
== s.outputs
{
@ -1195,7 +1195,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
}),
}
};
statements_checked.push(statement);
statements_checked.append(&mut statements);
}
Err(e) => {
errors.extend(e);
@ -1708,8 +1708,8 @@ impl<'ast, T: Field> Checker<'ast, T> {
let mut checked_statements = vec![];
for stat in statements {
let checked_stat = self.check_statement(stat, module_id, types)?;
checked_statements.push(checked_stat);
let mut checked_stat = self.check_statement(stat, module_id, types)?;
checked_statements.append(&mut checked_stat);
}
Ok(TypedStatement::For(var, from, to, checked_statements))
@ -1720,7 +1720,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
stat: StatementNode<'ast>,
module_id: &ModuleId,
types: &TypeMap<'ast, T>,
) -> Result<TypedStatement<'ast, T>, Vec<ErrorInner>> {
) -> Result<Vec<TypedStatement<'ast, T>>, Vec<ErrorInner>> {
let pos = stat.pos();
match stat.value {
@ -1749,8 +1749,10 @@ impl<'ast, T: Field> Checker<'ast, T> {
vec![ErrorInner {
pos: Some(pos),
message: format!(
"Expected return value to be of type {}, found {}",
e.1, e.0
"Expected return value to be of type {}, found {} of type {}",
e.1,
e.0,
e.0.get_type()
),
}]
}) {
@ -1799,12 +1801,61 @@ impl<'ast, T: Field> Checker<'ast, T> {
return Err(errors);
}
Ok(res)
Ok(vec![res])
}
Statement::Let(id, e) => {
// check the expression to be assigned
let checked_expr = self
.check_expression(e, module_id, types)
.map_err(|e| vec![e])?;
let ty = checked_expr.get_type();
let typed_expr = match ty {
Type::FieldElement => FieldElementExpression::try_from_typed(checked_expr)
.map(TypedExpression::from),
Type::Boolean => {
BooleanExpression::try_from_typed(checked_expr).map(TypedExpression::from)
}
Type::Uint(bitwidth) => UExpression::try_from_typed(checked_expr, &bitwidth)
.map(TypedExpression::from),
Type::Array(ref array_ty) => {
ArrayExpression::try_from_typed(checked_expr, array_ty)
.map(TypedExpression::from)
}
Type::Struct(ref struct_ty) => {
StructExpression::try_from_typed(checked_expr, struct_ty)
.map(TypedExpression::from)
}
Type::Int => Err(checked_expr), // Integers cannot be assigned
}
.map_err(|e| {
vec![ErrorInner {
pos: Some(pos),
message: format!(
"Expression `{}` of type `{}` cannot be assigned to `{}`",
e,
e.get_type(),
id
),
}]
})?;
let var = Variable::with_id_and_type(id, typed_expr.get_type());
match self.insert_into_scope(var.clone()) {
true => Ok(vec![
TypedStatement::Declaration(var.clone()),
TypedStatement::Definition(TypedAssignee::Identifier(var), typed_expr),
]),
false => Err(vec![ErrorInner {
pos: Some(pos),
message: format!("Duplicate declaration for variable named {}", var.id),
}]),
}
}
Statement::Declaration(var) => {
let var = self.check_variable(var, module_id, types)?;
match self.insert_into_scope(var.clone()) {
true => Ok(TypedStatement::Declaration(var)),
true => Ok(vec![TypedStatement::Declaration(var)]),
false => Err(ErrorInner {
pos: Some(pos),
message: format!("Duplicate declaration for variable named {}", var.id),
@ -1860,7 +1911,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
var_type
),
})
.map(|rhs| TypedStatement::Definition(var, rhs))
.map(|rhs| vec![TypedStatement::Definition(var, rhs)])
.map_err(|e| vec![e])
}
Statement::Assertion(e, message) => {
@ -1869,14 +1920,14 @@ impl<'ast, T: Field> Checker<'ast, T> {
.map_err(|e| vec![e])?;
match e {
TypedExpression::Boolean(e) => Ok(TypedStatement::Assertion(
TypedExpression::Boolean(e) => Ok(vec![TypedStatement::Assertion(
e,
RuntimeError::SourceAssertion(AssertionMetadata {
file: module_id.display().to_string(),
position: pos.0,
message,
}),
)),
)]),
e => Err(ErrorInner {
pos: Some(pos),
message: format!(
@ -1895,7 +1946,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
self.exit_scope();
res
res.map(|s| vec![s])
}
Statement::MultipleDefinition(assignees, rhs) => {
match rhs.value {
@ -1976,7 +2027,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
let call = TypedExpressionList::function_call(f.clone(), generics_checked.unwrap_or_else(|| vec![None; f.signature.generics.len()]), arguments_checked).annotate(Types { inner: assignees.iter().map(|a| a.get_type()).collect()});
Ok(TypedStatement::MultipleDefinition(assignees, call))
Ok(vec![TypedStatement::MultipleDefinition(assignees, call)])
},
0 => Err(ErrorInner { pos: Some(pos),
message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),

View file

@ -49,13 +49,15 @@ vis = { vis_private | vis_public }
// Statements
statement = { (return_statement // does not require subsequent newline
| (iteration_statement
| let_statement
| definition_statement
| expression_statement
) ~ NEWLINE
) ~ NEWLINE* }
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
return_statement = { "return" ~ expression_list}
return_statement = { "return" ~ expression_list }
let_statement = { "let" ~ identifier ~ "=" ~ expression }
definition_statement = { typed_identifier_or_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
expression_statement = {"assert" ~ "(" ~ expression ~ ("," ~ quoted_string)? ~ ")"}
@ -167,6 +169,7 @@ COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
// accepted
keyword = @{"assert"|"as"|"bool"|"const"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
"in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"|"u64"
}
keyword = @{
"assert"|"as"|"bool"|"const"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
"in"|"let"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"|"u64"
}

View file

@ -14,11 +14,11 @@ pub use ast::{
DecimalSuffix, DefinitionStatement, ExplicitGenerics, Expression, FieldType, File,
FromExpression, FunctionDefinition, HexLiteralExpression, HexNumberExpression,
IdentifierExpression, IfElseExpression, ImportDirective, ImportSymbol, InlineArrayExpression,
InlineStructExpression, InlineStructMember, IterationStatement, LiteralExpression, Parameter,
PostfixExpression, Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression,
Statement, StructDefinition, StructField, SymbolDeclaration, TernaryExpression, ToExpression,
Type, TypeDefinition, TypedIdentifier, TypedIdentifierOrAssignee, UnaryExpression,
UnaryOperator, Underscore, Visibility,
InlineStructExpression, InlineStructMember, IterationStatement, LetStatement,
LiteralExpression, Parameter, PostfixExpression, Range, RangeOrExpression, ReturnStatement,
Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField, SymbolDeclaration,
TernaryExpression, ToExpression, Type, TypeDefinition, TypedIdentifier,
TypedIdentifierOrAssignee, UnaryExpression, UnaryOperator, Underscore, Visibility,
};
mod ast {
@ -352,11 +352,21 @@ mod ast {
#[pest_ast(rule(Rule::statement))]
pub enum Statement<'ast> {
Return(ReturnStatement<'ast>),
Let(LetStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Assertion(AssertionStatement<'ast>),
Iteration(IterationStatement<'ast>),
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::let_statement))]
pub struct LetStatement<'ast> {
pub id: IdentifierExpression<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
#[derive(Debug, FromPest, PartialEq, Clone)]
#[pest_ast(rule(Rule::definition_statement))]
pub struct DefinitionStatement<'ast> {