Array literals in expressions.

This commit is contained in:
chriseth
2023-09-19 13:39:57 +02:00
parent 0ead3bd1c7
commit ac0ccff780
10 changed files with 65 additions and 14 deletions

View File

@@ -589,6 +589,7 @@ impl<T: FieldElement> ASMPILConverter<T> {
Expression::Number(value) => vec![(value, AffineExpressionComponent::Constant)],
Expression::String(_) => panic!(),
Expression::Tuple(_) => panic!(),
Expression::ArrayLiteral(_) => panic!(),
Expression::MatchExpression(_, _) => panic!(),
Expression::FreeInput(expr) => {
vec![(1.into(), AffineExpressionComponent::FreeInput(*expr))]

View File

@@ -433,6 +433,7 @@ impl<T: Display, Ref: Display> Display for Expression<T, Ref> {
Expression::String(value) => write!(f, "\"{value}\""), // TODO quote?
Expression::Tuple(items) => write!(f, "({})", format_expressions(items)),
Expression::LambdaExpression(lambda) => write!(f, "{}", lambda),
Expression::ArrayLiteral(array) => write!(f, "{array}"),
Expression::BinaryOperation(left, op, right) => write!(f, "({left} {op} {right})"),
Expression::UnaryOperation(op, exp) => write!(f, "{op}{exp}"),
Expression::FunctionCall(fun_call) => write!(f, "{fun_call}"),
@@ -504,6 +505,12 @@ impl<T: Display, Ref: Display> Display for LambdaExpression<T, Ref> {
}
}
impl<T: Display, Ref: Display> Display for ArrayLiteral<T, Ref> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "[{}]", self.items.iter().format(", "))
}
}
impl Display for BinaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(

View File

@@ -66,6 +66,7 @@ pub enum Expression<T, Ref = ShiftedPolynomialReference<T>> {
String(String),
Tuple(Vec<Expression<T, Ref>>),
LambdaExpression(LambdaExpression<T, Ref>),
ArrayLiteral(ArrayLiteral<T, Ref>),
BinaryOperation(
Box<Expression<T, Ref>>,
BinaryOperator,
@@ -271,6 +272,11 @@ pub struct LambdaExpression<T, Ref = ShiftedPolynomialReference<T>> {
pub body: Box<Expression<T, Ref>>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ArrayLiteral<T, Ref = ShiftedPolynomialReference<T>> {
pub items: Vec<Expression<T, Ref>>,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum UnaryOperator {
Plus,

View File

@@ -1,8 +1,8 @@
use std::{iter::once, ops::ControlFlow};
use super::{
ArrayExpression, Expression, FunctionCall, FunctionDefinition, LambdaExpression, MatchArm,
PilStatement,
ArrayExpression, ArrayLiteral, Expression, FunctionCall, FunctionDefinition, LambdaExpression,
MatchArm, PilStatement,
};
/// Visits `expr` and all of its sub-expressions and returns true if `f` returns true on any of them.
@@ -111,6 +111,7 @@ where
previsit_expression(e, f)?
}
Expression::Tuple(items)
| Expression::ArrayLiteral(ArrayLiteral { items })
| Expression::FunctionCall(FunctionCall {
id: _,
arguments: items,
@@ -152,6 +153,7 @@ where
previsit_expression_mut(e.as_mut(), f)?
}
Expression::Tuple(items)
| Expression::ArrayLiteral(ArrayLiteral { items })
| Expression::FunctionCall(FunctionCall {
arguments: items, ..
}) => items
@@ -190,6 +192,7 @@ where
postvisit_expression_mut(e.as_mut(), f)?
}
Expression::Tuple(items)
| Expression::ArrayLiteral(ArrayLiteral { items })
| Expression::FunctionCall(FunctionCall {
arguments: items, ..
}) => items

View File

@@ -311,6 +311,7 @@ impl<'a, T: FieldElement> Exporter<'a, T> {
Expression::FunctionCall(_) => panic!("No function calls allowed here."),
Expression::String(_) => panic!("Strings not allowed here."),
Expression::Tuple(_) => panic!("Tuples not allowed here"),
Expression::ArrayLiteral(_) => panic!("Array literals not allowed here"),
Expression::MatchExpression(_, _) => {
panic!("No match expressions allowed here.")
}

View File

@@ -97,6 +97,7 @@ impl<'a, T: FieldElement> Evaluator<'a, T> {
Expression::Number(n) => *n,
Expression::String(_) => panic!(),
Expression::Tuple(_) => panic!(),
Expression::ArrayLiteral(_) => panic!(),
Expression::BinaryOperation(left, op, right) => {
evaluate_binary_operation(self.evaluate(left), *op, self.evaluate(right))
}

View File

@@ -45,6 +45,7 @@ mod test {
SelectedExpressions,
};
use number::GoldilocksField;
use parser_util::UnwrapErrToStderr;
use std::fs;
use test_log::test;
@@ -115,11 +116,7 @@ mod test {
));
let input = fs::read_to_string(file).unwrap();
parse(Some(name), &input).unwrap_or_else(|err| {
eprintln!("Parse error during test:");
err.output_to_stderr();
panic!();
})
parse(Some(name), &input).unwrap_err_to_stderr()
}
fn parse_asm_file(name: &str) -> ASMProgram<GoldilocksField> {
@@ -129,11 +126,7 @@ mod test {
));
let input = fs::read_to_string(file).unwrap();
parse_asm(Some(name), &input).unwrap_or_else(|err| {
eprintln!("Parse error during test:");
err.output_to_stderr();
panic!();
})
parse_asm(Some(name), &input).unwrap_err_to_stderr()
}
#[test]
@@ -195,6 +188,7 @@ mod test {
mod display {
use number::GoldilocksField;
use parser_util::UnwrapErrToStderr;
use pretty_assertions::assert_eq;
use crate::parse;
@@ -248,5 +242,15 @@ public out = y(%last_row);"#;
);
assert_eq!(input.trim(), printed.trim());
}
#[test]
fn array_literals() {
let input = r#"let x = [[1], [2], [(3 + 7)]];"#;
let printed = format!(
"{}",
parse::<GoldilocksField>(Some("input"), input).unwrap_err_to_stderr()
);
assert_eq!(input.trim(), printed.trim());
}
}
}

View File

@@ -457,6 +457,7 @@ Term: Box<Expression<T>> = {
FieldElement => Box::new(Expression::Number(<>)),
StringLiteral => Box::new(Expression::String(<>)),
MatchExpression,
"[" <items:ExpressionList> "]" => Box::new(Expression::ArrayLiteral(ArrayLiteral{items})),
"(" <head:Expression> "," <tail:ExpressionList> ")" => { let mut list = vec![head]; list.extend(tail); Box::new(Expression::Tuple(list)) },
"(" <BoxedExpression> ")",
"${" <BoxedExpression> "}" => Box::new(Expression::FreeInput(<>))

View File

@@ -57,3 +57,24 @@ pub fn handle_parse_error<'a>(
message: format!("{err}"),
}
}
/// Convenience trait that outputs parser errors to stderr and panics.
/// Should be used mostly in tests.
pub trait UnwrapErrToStderr {
type Inner;
fn unwrap_err_to_stderr(self) -> Self::Inner;
}
impl<'a, T> UnwrapErrToStderr for Result<T, ParseError<'a>> {
type Inner = T;
fn unwrap_err_to_stderr(self) -> Self::Inner {
match self {
Ok(r) => r,
Err(err) => {
err.output_to_stderr();
panic!("Parse error.");
}
}
}
}

View File

@@ -5,8 +5,8 @@ use std::path::{Path, PathBuf};
use analysis::MacroExpander;
use ast::parsed::utils::postvisit_expression_mut;
use ast::parsed::{
self, ArrayExpression, BinaryOperator, FunctionDefinition, LambdaExpression, MatchArm,
MatchPattern, PilStatement, PolynomialName, UnaryOperator,
self, ArrayExpression, ArrayLiteral, BinaryOperator, FunctionDefinition, LambdaExpression,
MatchArm, MatchPattern, PilStatement, PolynomialName, UnaryOperator,
};
use number::{DegreeType, FieldElement};
@@ -521,6 +521,11 @@ impl<T: FieldElement> PILContext<T> {
PExpression::Number(n) => Expression::Number(n),
PExpression::String(value) => Expression::String(value),
PExpression::Tuple(items) => Expression::Tuple(self.process_expressions(items)),
PExpression::ArrayLiteral(ArrayLiteral { items }) => {
Expression::ArrayLiteral(ArrayLiteral {
items: self.process_expressions(items),
})
}
PExpression::LambdaExpression(LambdaExpression { params, body }) => {
Expression::LambdaExpression(LambdaExpression {
params,
@@ -618,6 +623,7 @@ impl<T: FieldElement> PILContext<T> {
Number(n) => Some(*n),
String(_) => None,
Tuple(_) => None,
ArrayLiteral(_) => None,
LambdaExpression(_) => None,
BinaryOperation(left, op, right) => self.evaluate_binary_operation(left, *op, right),
UnaryOperation(op, value) => self.evaluate_unary_operation(*op, value),