Merge pull request #1866 from AleoHQ/method-call-expr

Implement AVM instructions as Leo method calls
This commit is contained in:
Collin Chin 2022-06-20 12:21:07 -07:00 committed by GitHub
commit c95c920f04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
517 changed files with 12621 additions and 1187 deletions

View File

@ -15,87 +15,132 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use super::*;
use leo_span::{sym, Symbol};
/// A binary operator.
///
/// Precedence is defined in the parser.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinaryOperation {
/// Addition, i.e. `+`.
/// Addition, i.e. `+`, `.add()`.
Add,
/// Subtraction, i.e. `-`.
Sub,
/// Multiplication, i.e. `*`.
Mul,
/// Division, i.e. `/`.
Div,
/// Exponentiation, i.e. `**` in `a ** b`.
Pow,
/// Logical-or, i.e., `||`.
Or,
/// Logical-and, i.e., `&&`.
/// Wrapping addition, i.e. `.add_wrapped()`.
AddWrapped,
/// Logical AND, i.e. `&&`.
And,
/// Equality relation, i.e., `==`.
/// Bitwise AND, i.e. `&`, `.and()`.
BitwiseAnd,
/// Division, i.e. `/`, `.div()`.
Div,
/// Wrapping division, i.e. `.div_wrapped()`.
DivWrapped,
/// Equality relation, i.e. `==`, `.eq()`.
Eq,
/// In-equality relation, i.e. `!=`.
Ne,
/// Greater-or-equal relation, i.e. `>=`.
/// Greater-or-equal relation, i.e. `>=`, `.ge()`.
Ge,
/// Greater-than relation, i.e. `>=`.
/// Greater-than relation, i.e. `>`, `.gt()`.
Gt,
/// Lesser-or-equal relation, i.e. `<=`.
/// Lesser-or-equal relation, i.e. `<=`, `.le()`.
Le,
/// Lesser-than relation, i.e. `<`.
/// Lesser-than relation, i.e. `<`, `.lt()`.
Lt,
}
/// The category a binary operation belongs to.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinaryOperationClass {
/// A numeric one, that is, the result is numeric.
Numeric,
/// A boolean one, meaning the result is of type `bool`.
Boolean,
}
impl AsRef<str> for BinaryOperation {
fn as_ref(&self) -> &'static str {
match self {
BinaryOperation::Add => "+",
BinaryOperation::Sub => "-",
BinaryOperation::Mul => "*",
BinaryOperation::Div => "/",
BinaryOperation::Pow => "**",
BinaryOperation::Or => "||",
BinaryOperation::And => "&&",
BinaryOperation::Eq => "==",
BinaryOperation::Ne => "!=",
BinaryOperation::Ge => ">=",
BinaryOperation::Gt => ">",
BinaryOperation::Le => "<=",
BinaryOperation::Lt => "<",
}
}
/// Multiplication, i.e. `*`, `.mul()`.
Mul,
/// Wrapping multiplication, i.e. `.mul_wrapped()`.
MulWrapped,
/// Boolean NAND, i.e. `.nand()`.
Nand,
/// In-equality relation, i.e. `!=`, `.neq()`.
Neq,
/// Boolean NOR, i.e. `.nor()`.
Nor,
/// Logical OR, i.e. `||`.
Or,
/// Bitwise OR, i.e. `|`, `.or()`.
BitwiseOr,
/// Exponentiation, i.e. `**` in `a ** b`, `.pow()`.
Pow,
/// Wrapping exponentiation, i.e. `.pow_wrapped()`.
PowWrapped,
/// Shift left operation, i.e. `<<`, `.shl()`.
Shl,
/// Wrapping shift left operation, i.e. `<<`, `.shl_wrapped()`.
ShlWrapped,
/// Shift right operation, i.e. >>, `.shr()`.
Shr,
/// Wrapping shift right operation, i.e. >>, `.shr_wrapped()`.
ShrWrapped,
/// Subtraction, i.e. `-`, `.sub()`.
Sub,
/// Wrapped subtraction, i.e. `.sub_wrapped()`.
SubWrapped,
/// Bitwise XOR, i.e. `.xor()`.
Xor,
}
impl BinaryOperation {
/// The class ("category") that the binary operation belongs to.
/// For example, the `+` operator is numeric and `==` results in a boolean value.
pub fn class(&self) -> BinaryOperationClass {
/// Returns a `BinaryOperation` from the given `Symbol`.
pub fn from_symbol(symbol: Symbol) -> Option<Self> {
Some(match symbol {
sym::add => Self::Add,
sym::add_wrapped => Self::AddWrapped,
sym::and => Self::BitwiseAnd,
sym::div => Self::Div,
sym::div_wrapped => Self::DivWrapped,
sym::eq => Self::Eq,
sym::ge => Self::Ge,
sym::gt => Self::Gt,
sym::le => Self::Le,
sym::lt => Self::Lt,
sym::mul => Self::Mul,
sym::mul_wrapped => Self::MulWrapped,
sym::nand => Self::Nand,
sym::neq => Self::Neq,
sym::nor => Self::Nor,
sym::or => Self::BitwiseOr,
sym::pow => Self::Pow,
sym::pow_wrapped => Self::PowWrapped,
sym::shl => Self::Shl,
sym::shl_wrapped => Self::ShlWrapped,
sym::shr => Self::Shr,
sym::shr_wrapped => Self::ShrWrapped,
sym::sub => Self::Sub,
sym::sub_wrapped => Self::SubWrapped,
sym::xor => Self::Xor,
_ => return None,
})
}
/// Represents the operator as a string.
fn as_str(self) -> &'static str {
match self {
BinaryOperation::Add
| BinaryOperation::Sub
| BinaryOperation::Mul
| BinaryOperation::Div
| BinaryOperation::Pow => BinaryOperationClass::Numeric,
BinaryOperation::Or
| BinaryOperation::And
| BinaryOperation::Eq
| BinaryOperation::Ne
| BinaryOperation::Ge
| BinaryOperation::Gt
| BinaryOperation::Le
| BinaryOperation::Lt => BinaryOperationClass::Boolean,
Self::Add => "add",
Self::AddWrapped => "add_wrapped",
Self::And => "&&",
Self::BitwiseAnd => "and",
Self::Div => "div",
Self::DivWrapped => "div_wrapped",
Self::Eq => "eq",
Self::Ge => "ge",
Self::Gt => "gt",
Self::Le => "le",
Self::Lt => "lt",
Self::Mul => "mul",
Self::MulWrapped => "mul_wrapped",
Self::Nand => "nand",
Self::Neq => "neq",
Self::Nor => "nor",
Self::Or => "||",
Self::BitwiseOr => "or",
Self::Pow => "pow",
Self::PowWrapped => "pow_wrapped",
Self::Shl => "shl",
Self::ShlWrapped => "shl_wrapped",
Self::Shr => "shr",
Self::ShrWrapped => "shr_wrapped",
Self::Sub => "sub",
Self::SubWrapped => "sub_wrapped",
Self::Xor => "xor",
}
}
}
@ -116,7 +161,7 @@ pub struct BinaryExpression {
impl fmt::Display for BinaryExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {}", self.left, self.op.as_ref(), self.right)
write!(f, "{}.{}({})", self.left, self.op.as_str(), self.right)
}
}

View File

@ -46,7 +46,7 @@ pub enum Expression {
Unary(UnaryExpression),
/// A ternary conditional expression `cond ? if_expr : else_expr`.
Ternary(TernaryExpression),
/// A call expression like `my_fun(args)`.
/// A call expression, e.g., `my_fun(args)`.
Call(CallExpression),
/// An expression of type "error".
/// Will result in a compile error eventually.

View File

@ -15,22 +15,56 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use super::*;
use leo_span::{sym, Symbol};
/// A unary operator for a unary expression.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnaryOperation {
/// The logical negation operator, i.e., `!`.
/// For example, it transforms `true` to `false`.
Not,
/// The arithmetic negation operator, i.e., `-`.
/// Absolute value checking for overflow, i.e. `.abs()`.
Abs,
/// Absolute value wrapping around at the boundary of the type, i.e. `.abs_wrapped()`.
AbsWrapped,
/// Double operation, i.e. `.double()`.
Double,
/// Multiplicative inverse, i.e. `.inv()`.
Inverse,
/// Negate operation, i.e. `.neg()`.
Negate,
/// Bitwise NOT, i.e. `!`, `.not()`.
Not,
/// Square operation, i.e. `.square()`.
Square,
/// Square root operation, i.e. `.sqrt()`.
SquareRoot,
}
impl AsRef<str> for UnaryOperation {
fn as_ref(&self) -> &'static str {
impl UnaryOperation {
/// Returns a `UnaryOperation` from the given `Symbol`.
pub fn from_symbol(symbol: Symbol) -> Option<Self> {
Some(match symbol {
sym::abs => Self::Abs,
sym::abs_wrapped => Self::AbsWrapped,
sym::double => Self::Double,
sym::inv => Self::Inverse,
sym::neg => Self::Negate,
sym::not => Self::Not,
sym::square => Self::Square,
sym::sqrt => Self::SquareRoot,
_ => return None,
})
}
/// Represents the opera.tor as a string.
fn as_str(self) -> &'static str {
match self {
UnaryOperation::Not => "!",
UnaryOperation::Negate => "-",
Self::Abs => "abs",
Self::AbsWrapped => "abs_wrapped",
Self::Double => "double",
Self::Inverse => "inv",
Self::Negate => "neg",
Self::Not => "not",
Self::Square => "square",
Self::SquareRoot => "sqrt",
}
}
}
@ -39,7 +73,7 @@ impl AsRef<str> for UnaryOperation {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnaryExpression {
/// The inner expression `op` is applied to.
pub inner: Box<Expression>,
pub receiver: Box<Expression>,
/// The unary operator to apply to `inner`.
pub op: UnaryOperation,
/// The span covering `op inner`.
@ -48,7 +82,7 @@ pub struct UnaryExpression {
impl fmt::Display for UnaryExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.op.as_ref(), self.inner)
write!(f, "{}{}", self.op.as_str(), self.receiver)
}
}

View File

@ -28,7 +28,7 @@ pub struct Function {
pub identifier: Identifier,
/// The function's parameters.
pub input: Vec<FunctionInput>,
/// The function return type, if explicitly specified, or `()` if not.
/// The function's required return type.
pub output: Type,
/// Any mapping to the core library.
/// Always `None` when initially parsed.

View File

@ -55,7 +55,7 @@ impl TryFrom<(Type, Expression)> for InputValue {
}
}
(type_, Expression::Unary(unary)) if unary.op == UnaryOperation::Negate => {
InputValue::try_from((type_, *unary.inner))?
InputValue::try_from((type_, *unary.receiver))?
}
(_type_, expr) => return Err(InputError::illegal_expression(&expr, expr.span()).into()),
})

View File

@ -93,9 +93,9 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
}
pub fn reduce_unary(&mut self, unary: &UnaryExpression) -> Result<UnaryExpression> {
let inner = self.reduce_expression(&unary.inner)?;
let inner = self.reduce_expression(&unary.receiver)?;
self.reducer.reduce_unary(unary, inner, unary.op.clone())
self.reducer.reduce_unary(unary, inner, unary.op)
}
pub fn reduce_ternary(&mut self, ternary: &TernaryExpression) -> Result<TernaryExpression> {

View File

@ -89,7 +89,7 @@ pub trait ReconstructingReducer {
op: UnaryOperation,
) -> Result<UnaryExpression> {
Ok(UnaryExpression {
inner: Box::new(inner),
receiver: Box::new(inner),
op,
span: unary.span,
})

View File

@ -72,7 +72,7 @@ pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor_ref().visit_unary(input) {
self.visit_expression(&input.inner, additional);
self.visit_expression(&input.receiver, additional);
}
None
}

View File

@ -56,16 +56,16 @@ impl ParserContext<'_> {
/// Returns an [`Expression`] AST node if the next tokens represent
/// a ternary expression. May or may not include circuit init expressions.
///
/// Otherwise, tries to parse the next token using [`parse_disjunctive_expression`].
/// Otherwise, tries to parse the next token using [`parse_boolean_or_expression`].
pub(super) fn parse_conditional_expression(&mut self) -> Result<Expression> {
// Try to parse the next expression. Try BinaryOperation::Or.
let mut expr = self.parse_disjunctive_expression()?;
let mut expr = self.parse_boolean_or_expression()?;
// Parse the rest of the ternary expression.
if self.eat(&Token::Question) {
let if_true = self.parse_expression()?;
self.expect(&Token::Colon)?;
let if_false = self.parse_conditional_expression()?;
let if_false = self.parse_expression()?;
expr = Expression::Ternary(TernaryExpression {
span: expr.span() + if_false.span(),
condition: Box::new(expr),
@ -100,27 +100,27 @@ impl ParserContext<'_> {
Ok(expr)
}
/// Returns an [`Expression`] AST node if the next tokens represent
/// a binary or expression.
///
/// Otherwise, tries to parse the next token using [`parse_conjunctive_expression`].
fn parse_disjunctive_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::Or], Self::parse_conjunctive_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// binary and expression.
/// binary AND expression.
///
/// Otherwise, tries to parse the next token using [`parse_equality_expression`].
fn parse_conjunctive_expression(&mut self) -> Result<Expression> {
fn parse_boolean_and_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::And], Self::parse_equality_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent
/// a binary OR expression.
///
/// Otherwise, tries to parse the next token using [`parse_boolean_and_expression`].
fn parse_boolean_or_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::Or], Self::parse_boolean_and_expression)
}
/// Eats one of binary operators matching any in `tokens`.
fn eat_bin_op(&mut self, tokens: &[Token]) -> Option<BinaryOperation> {
self.eat_any(tokens).then(|| match &self.prev_token.token {
Token::Eq => BinaryOperation::Eq,
Token::NotEq => BinaryOperation::Ne,
Token::NotEq => BinaryOperation::Neq,
Token::Lt => BinaryOperation::Lt,
Token::LtEq => BinaryOperation::Le,
Token::Gt => BinaryOperation::Gt,
@ -131,11 +131,29 @@ impl ParserContext<'_> {
Token::Div => BinaryOperation::Div,
Token::Or => BinaryOperation::Or,
Token::And => BinaryOperation::And,
Token::BitwiseOr => BinaryOperation::BitwiseOr,
Token::BitwiseAnd => BinaryOperation::BitwiseAnd,
Token::Exp => BinaryOperation::Pow,
Token::Shl => BinaryOperation::Shl,
Token::Shr => BinaryOperation::Shr,
Token::Xor => BinaryOperation::Xor,
_ => unreachable!("`eat_bin_op` shouldn't produce this"),
})
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// binary relational expression: less than, less than or equals, greater than, greater than or equals.
///
/// Otherwise, tries to parse the next token using [`parse_additive_expression`].
fn parse_ordering_expression(&mut self) -> Result<Expression> {
let mut expr = self.parse_bitwise_exclusive_or_expression()?;
if let Some(op) = self.eat_bin_op(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) {
let right = self.parse_bitwise_exclusive_or_expression()?;
expr = Self::bin_expr(expr, right, op);
}
Ok(expr)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// binary equals or not equals expression.
///
@ -150,16 +168,35 @@ impl ParserContext<'_> {
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// binary relational expression: less than, less than or equals, greater than, greater than or equals.
/// bitwise exclusive or expression.
///
/// Otherwise, tries to parse the next token using [`parse_bitwise_inclusive_or_expression`].
fn parse_bitwise_exclusive_or_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::Xor], Self::parse_bitwise_inclusive_or_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// bitwise inclusive or expression.
///
/// Otherwise, tries to parse the next token using [`parse_bitwise_and_expression`].
fn parse_bitwise_inclusive_or_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::BitwiseOr], Self::parse_bitwise_and_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// bitwise and expression.
///
/// Otherwise, tries to parse the next token using [`parse_shift_expression`].
fn parse_bitwise_and_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::BitwiseAnd], Self::parse_shift_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// shift left or a shift right expression.
///
/// Otherwise, tries to parse the next token using [`parse_additive_expression`].
fn parse_ordering_expression(&mut self) -> Result<Expression> {
let mut expr = self.parse_additive_expression()?;
if let Some(op) = self.eat_bin_op(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) {
let right = self.parse_additive_expression()?;
expr = Self::bin_expr(expr, right, op);
}
Ok(expr)
fn parse_shift_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr(&[Token::Shl, Token::Shr], Self::parse_additive_expression)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
@ -212,12 +249,49 @@ impl ParserContext<'_> {
inner = Expression::Unary(UnaryExpression {
span: op_span + inner.span(),
op,
inner: Box::new(inner),
receiver: Box::new(inner),
});
}
Ok(inner)
}
/// Returns an [`Expression`] AST node if the next tokens represent a
/// method call expression.
fn parse_method_call_expression(&mut self, receiver: Expression) -> Result<Expression> {
// Parse the method name.
let method = self.expect_ident()?;
// Parse the argument list.
let (mut args, _, span) = self.parse_expr_tuple()?;
let span = receiver.span() + span;
if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
// Found an unary operator and the argument list is empty.
Ok(Expression::Unary(UnaryExpression {
span,
op,
receiver: Box::new(receiver),
}))
} else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) {
// Found a binary operator and the argument list contains a single argument.
Ok(Expression::Binary(BinaryExpression {
span,
op,
left: Box::new(receiver),
right: Box::new(args.swap_remove(0)),
}))
} else {
// Either an invalid unary/binary operator, or more arguments given.
self.emit_err(ParserError::expr_arbitrary_method_call(span));
Ok(Expression::Err(ErrExpression { span }))
}
}
/// Parses a tuple of expressions.
fn parse_expr_tuple(&mut self) -> Result<(Vec<Expression>, bool, Span)> {
self.parse_paren_comma_list(|p| p.parse_expression().map(Some))
}
/// Returns an [`Expression`] AST node if the next tokens represent an
/// array access, circuit member access, function call, or static function call expression.
///
@ -229,20 +303,21 @@ impl ParserContext<'_> {
let mut expr = self.parse_primary_expression()?;
loop {
if self.eat(&Token::Dot) {
let curr = &self.token;
return Err(ParserError::unexpected_str(&curr.token, "int or ident", curr.span).into());
// Eat a method call on a type
expr = self.parse_method_call_expression(expr)?
} else if self.check(&Token::LeftParen) {
// Parse a function call that's by itself.
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
expr = Expression::Call(CallExpression {
span: expr.span() + span,
function: Box::new(expr),
arguments,
});
}
if !self.check(&Token::LeftParen) {
// Check if next token is a dot to see if we are calling recursive method.
if !self.check(&Token::Dot) {
break;
}
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
expr = Expression::Call(CallExpression {
span: expr.span() + span,
function: Box::new(expr),
arguments,
});
}
Ok(expr)
}
@ -256,10 +331,10 @@ impl ParserContext<'_> {
)))));
}
let (mut tuple, trailing, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
let (mut tuple, trailing, span) = self.parse_expr_tuple()?;
if !trailing && tuple.len() == 1 {
Ok(tuple.remove(0))
Ok(tuple.swap_remove(0))
} else {
Err(ParserError::unexpected("A tuple expression.", "A valid expression.", span).into())
}

View File

@ -192,16 +192,16 @@ impl Token {
(1, els)
})
};
// Consumes `on` again and produces `token` if found.
let twice = |input: &mut Peekable<_>, on, token| {
// Consumes a character followed by `on_1`, `on_2` or none. Outputs case_1, case_2, or els.
let three_cases = |input: &mut Peekable<_>, on_1, case_1, on_2, case_2, els| {
input.next();
if input.next_if_eq(&on).is_some() {
Ok((2, token))
} else if let Some(found) = input.next() {
Err(ParserError::lexer_expected_but_found(found, on).into())
Ok(if input.next_if_eq(&on_1).is_some() {
(2, case_1)
} else if input.next_if_eq(&on_2).is_some() {
(2, case_2)
} else {
Err(ParserError::lexer_empty_input().into())
}
(1, els)
})
};
match *input.peek().ok_or_else(ParserError::lexer_empty_input)? {
@ -236,7 +236,7 @@ impl Token {
x if x.is_ascii_digit() => return Self::eat_integer(&mut input),
'!' => return followed_by(&mut input, '=', Token::NotEq, Token::Not),
'?' => return single(&mut input, Token::Question),
'&' => return twice(&mut input, '&', Token::And),
'&' => return followed_by(&mut input, '&', Token::And, Token::BitwiseAnd),
'(' => return single(&mut input, Token::LeftParen),
')' => return single(&mut input, Token::RightParen),
'_' => return single(&mut input, Token::Underscore),
@ -292,14 +292,15 @@ impl Token {
}
':' => return single(&mut input, Token::Colon),
';' => return single(&mut input, Token::Semicolon),
'<' => return followed_by(&mut input, '=', Token::LtEq, Token::Lt),
'>' => return followed_by(&mut input, '=', Token::GtEq, Token::Gt),
'<' => return three_cases(&mut input, '=', Token::LtEq, '<', Token::Shl, Token::Lt),
'>' => return three_cases(&mut input, '=', Token::GtEq, '>', Token::Shr, Token::Gt),
'=' => return followed_by(&mut input, '=', Token::Eq, Token::Assign),
'[' => return single(&mut input, Token::LeftSquare),
']' => return single(&mut input, Token::RightSquare),
'{' => return single(&mut input, Token::LeftCurly),
'}' => return single(&mut input, Token::RightCurly),
'|' => return twice(&mut input, '|', Token::Or),
'|' => return followed_by(&mut input, '|', Token::Or, Token::BitwiseOr),
'^' => return single(&mut input, Token::Xor),
_ => (),
}
if let Some(ident) = eat_identifier(&mut input) {

View File

@ -38,6 +38,8 @@ pub enum Token {
Not,
And,
Or,
BitwiseAnd,
BitwiseOr,
Eq,
NotEq,
Lt,
@ -63,7 +65,10 @@ pub enum Token {
Colon,
Question,
Arrow,
Shl,
Shr,
Underscore,
Xor,
// Syntactic Grammar
// Types
@ -200,6 +205,8 @@ impl fmt::Display for Token {
Not => write!(f, "!"),
And => write!(f, "&&"),
Or => write!(f, "||"),
BitwiseAnd => write!(f, "&"),
BitwiseOr => write!(f, "|"),
Eq => write!(f, "=="),
NotEq => write!(f, "!="),
Lt => write!(f, "<"),
@ -225,7 +232,10 @@ impl fmt::Display for Token {
Colon => write!(f, ":"),
Question => write!(f, "?"),
Arrow => write!(f, "->"),
Shl => write!(f, "<<"),
Shr => write!(f, ">>"),
Underscore => write!(f, "_"),
Xor => write!(f, "^"),
Address => write!(f, "address"),
Bool => write!(f, "bool"),

View File

@ -64,7 +64,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor.visit_identifier(input) {
return if let Some(var) = self.visitor.symbol_table.clone().lookup_variable(&input.name) {
Some(self.visitor.assert_type(*var.type_, expected, var.span))
Some(self.visitor.assert_expected_option(*var.type_, expected, input.span))
} else {
self.visitor
.handler
@ -79,9 +79,17 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
fn visit_value(&mut self, input: &'a ValueExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor.visit_value(input) {
return Some(match input {
ValueExpression::Address(_, _) => self.visitor.assert_type(Type::Address, expected, input.span()),
ValueExpression::Boolean(_, _) => self.visitor.assert_type(Type::Boolean, expected, input.span()),
ValueExpression::Field(_, _) => self.visitor.assert_type(Type::Field, expected, input.span()),
ValueExpression::Address(_, _) => {
self.visitor
.assert_expected_option(Type::Address, expected, input.span())
}
ValueExpression::Boolean(_, _) => {
self.visitor
.assert_expected_option(Type::Boolean, expected, input.span())
}
ValueExpression::Field(_, _) => {
self.visitor.assert_expected_option(Type::Field, expected, input.span())
}
ValueExpression::Integer(type_, str_content, _) => {
match type_ {
IntegerType::I8 => {
@ -172,143 +180,234 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
_ => {}
}
self.visitor
.assert_type(Type::IntegerType(*type_), expected, input.span())
.assert_expected_option(Type::IntegerType(*type_), expected, input.span())
}
ValueExpression::Group(_) => self.visitor.assert_expected_option(Type::Group, expected, input.span()),
ValueExpression::Scalar(_, _) => {
self.visitor
.assert_expected_option(Type::Scalar, expected, input.span())
}
ValueExpression::String(_, _) => {
self.visitor
.assert_expected_option(Type::String, expected, input.span())
}
ValueExpression::Group(_) => self.visitor.assert_type(Type::Group, expected, input.span()),
ValueExpression::Scalar(_, _) => self.visitor.assert_type(Type::Scalar, expected, input.span()),
ValueExpression::String(_, _) => self.visitor.assert_type(Type::String, expected, input.span()),
});
}
None
}
fn visit_binary(&mut self, input: &'a BinaryExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
fn visit_binary(
&mut self,
input: &'a BinaryExpression,
destination: &Self::AdditionalInput,
) -> Option<Self::Output> {
if let VisitResult::VisitChildren = self.visitor.visit_binary(input) {
return match input.op {
BinaryOperation::And | BinaryOperation::Or => {
self.visitor.assert_type(Type::Boolean, expected, input.span());
let t1 = self.visit_expression(&input.left, expected);
let t2 = self.visit_expression(&input.right, expected);
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
// Assert equal boolean types.
self.visitor
.assert_expected_option(Type::Boolean, destination, input.span());
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, expected)
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
// Assert equal boolean or integer types.
self.visitor.assert_bool_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::Add => {
self.visitor.assert_field_group_scalar_int_type(expected, input.span());
let t1 = self.visit_expression(&input.left, expected);
let t2 = self.visit_expression(&input.right, expected);
// Assert equal field, group, scalar, or integer types.
self.visitor
.assert_field_group_scalar_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, expected)
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::Sub => {
self.visitor.assert_field_group_int_type(expected, input.span());
let t1 = self.visit_expression(&input.left, expected);
let t2 = self.visit_expression(&input.right, expected);
// Assert equal field, group, or integer types.
self.visitor.assert_field_group_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, expected)
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::Mul => {
self.visitor.assert_field_group_int_type(expected, input.span());
// Assert field, group or integer types.
self.visitor.assert_field_group_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, &None);
let t2 = self.visit_expression(&input.right, &None);
// Allow `group` * `scalar` multiplication.
match (t1.as_ref(), t2.as_ref()) {
(Some(Type::Group), Some(other)) => {
self.visitor.assert_type(Type::Group, expected, input.left.span());
match (t1, t2) {
(Some(Type::Group), other) => {
self.visitor
.assert_type(*other, &Some(Type::Scalar), input.right.span());
Some(Type::Group)
.assert_expected_type(&other, Type::Scalar, input.right.span());
Some(
self.visitor
.assert_expected_type(destination, Type::Group, input.span()),
)
}
(Some(other), Some(Type::Group)) => {
self.visitor.assert_type(*other, &Some(Type::Scalar), input.left.span());
self.visitor.assert_type(Type::Group, expected, input.right.span());
Some(Type::Group)
(other, Some(Type::Group)) => {
self.visitor
.assert_expected_type(&other, Type::Scalar, input.left.span());
Some(
self.visitor
.assert_expected_type(destination, Type::Group, input.span()),
)
}
(Some(t1), Some(t2)) => {
self.visitor.assert_type(*t1, expected, input.left.span());
self.visitor.assert_type(*t2, expected, input.right.span());
return_incorrect_type(Some(*t1), Some(*t2), expected)
(t1, t2) => {
// Assert equal field or integer types.
self.visitor.assert_field_int_type(destination, input.span());
return_incorrect_type(t1, t2, destination)
}
(Some(type_), None) => {
self.visitor.assert_type(*type_, expected, input.left.span());
None
}
(None, Some(type_)) => {
self.visitor.assert_type(*type_, expected, input.right.span());
None
}
(None, None) => None,
}
}
BinaryOperation::Div => {
self.visitor.assert_field_int_type(expected, input.span());
// Assert equal field or integer types.
self.visitor.assert_field_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, expected);
let t2 = self.visit_expression(&input.right, expected);
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, expected)
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::Pow => {
// Assert field or integer types.
self.visitor.assert_field_int_type(destination, input.span());
let t1 = self.visit_expression(&input.left, &None);
let t2 = self.visit_expression(&input.right, &None);
match (t1.as_ref(), t2.as_ref()) {
// Type A must be an int.
// Type B must be a unsigned int.
(Some(Type::IntegerType(_)), Some(Type::IntegerType(itype))) if !itype.is_signed() => {
self.visitor.assert_type(t1.unwrap(), expected, input.left.span());
}
// Type A was an int.
// But Type B was not a unsigned int.
(Some(Type::IntegerType(_)), Some(t)) => {
self.visitor.handler.emit_err(
TypeCheckerError::incorrect_pow_exponent_type("unsigned int", t, input.right.span())
.into(),
);
}
// Type A must be a field.
// Type B must be an int.
(Some(Type::Field), Some(Type::IntegerType(_))) => {
self.visitor.assert_type(Type::Field, expected, input.left.span());
}
// Type A was a field.
// But Type B was not an int.
(Some(Type::Field), Some(t)) => {
self.visitor.handler.emit_err(
TypeCheckerError::incorrect_pow_exponent_type("int", t, input.right.span()).into(),
);
}
// The base is some type thats not an int or field.
(Some(t), _) if !matches!(t, Type::IntegerType(_) | Type::Field) => {
// Allow field * field.
match (t1, t2) {
(Some(Type::Field), type_) => {
self.visitor
.handler
.emit_err(TypeCheckerError::incorrect_pow_base_type(t, input.left.span()).into());
.assert_expected_type(&type_, Type::Field, input.right.span());
Some(
self.visitor
.assert_expected_type(destination, Type::Field, input.span()),
)
}
(type_, Some(Type::Field)) => {
self.visitor
.assert_expected_type(&type_, Type::Field, input.left.span());
Some(
self.visitor
.assert_expected_type(destination, Type::Field, input.span()),
)
}
(Some(t1), t2) => {
// Allow integer t2 magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.right.span());
Some(self.visitor.assert_expected_type(destination, t1, input.span()))
}
(None, t2) => {
// Allow integer t2 magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.right.span());
*destination
}
}
}
BinaryOperation::Eq | BinaryOperation::Neq => {
// Assert first and second address, boolean, field, group, scalar, or integer types.
let t1 = self.visit_expression(&input.left, &None);
let t2 = self.visit_expression(&input.right, &None);
match (t1, t2) {
(Some(Type::IntegerType(_)), t2) => {
// Assert rhs is integer.
self.visitor.assert_int_type(&t2, input.left.span());
}
(t1, Some(Type::IntegerType(_))) => {
// Assert lhs is integer.
self.visitor.assert_int_type(&t1, input.right.span());
}
(t1, t2) => {
self.visitor.assert_eq_types(t1, t2, input.span());
}
_ => {}
}
t1
}
BinaryOperation::Eq | BinaryOperation::Ne => {
let t1 = self.visit_expression(&input.left, &None);
let t2 = self.visit_expression(&input.right, &None);
self.visitor.assert_eq_types(t1, t2, input.span());
Some(Type::Boolean)
// Assert destination is boolean.
Some(
self.visitor
.assert_expected_type(destination, Type::Boolean, input.span()),
)
}
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Le | BinaryOperation::Ge => {
// Assert left and right are equal field, scalar, or integer types.
let t1 = self.visit_expression(&input.left, &None);
self.visitor.assert_field_scalar_int_type(&t1, input.left.span());
let t2 = self.visit_expression(&input.right, &None);
self.visitor.assert_field_scalar_int_type(&t2, input.right.span());
self.visitor.assert_eq_types(t1, t2, input.span());
match (t1, t2) {
(Some(Type::Field), t2) => {
// Assert rhs is field.
self.visitor.assert_expected_type(&t2, Type::Field, input.left.span());
}
(t1, Some(Type::Field)) => {
// Assert lhs is field.
self.visitor.assert_expected_type(&t1, Type::Field, input.right.span());
}
(Some(Type::Scalar), t2) => {
// Assert rhs is scalar.
self.visitor.assert_expected_type(&t2, Type::Scalar, input.left.span());
}
(t1, Some(Type::Scalar)) => {
// Assert lhs is scalar.
self.visitor.assert_expected_type(&t1, Type::Scalar, input.right.span());
}
(Some(Type::IntegerType(_)), t2) => {
// Assert rhs is integer.
self.visitor.assert_int_type(&t2, input.left.span());
}
(t1, Some(Type::IntegerType(_))) => {
// Assert lhs is integer.
self.visitor.assert_int_type(&t1, input.right.span());
}
(_, _) => {
// Not enough info to assert type.
}
}
Some(Type::Boolean)
// Assert destination is boolean.
Some(
self.visitor
.assert_expected_type(destination, Type::Boolean, input.span()),
)
}
BinaryOperation::AddWrapped
| BinaryOperation::SubWrapped
| BinaryOperation::DivWrapped
| BinaryOperation::MulWrapped => {
// Assert equal integer types.
self.visitor.assert_int_type(destination, input.span);
let t1 = self.visit_expression(&input.left, destination);
let t2 = self.visit_expression(&input.right, destination);
return_incorrect_type(t1, t2, destination)
}
BinaryOperation::Shl
| BinaryOperation::ShlWrapped
| BinaryOperation::Shr
| BinaryOperation::ShrWrapped
| BinaryOperation::PowWrapped => {
// Assert left and destination are equal integer types.
self.visitor.assert_int_type(destination, input.span);
let t1 = self.visit_expression(&input.left, destination);
// Assert right type is a magnitude (u8, u16, u32).
let t2 = self.visit_expression(&input.right, &None);
self.visitor.assert_magnitude_type(&t2, input.right.span());
return_incorrect_type(t1, t2, destination)
}
};
}
@ -316,17 +415,34 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
None
}
fn visit_unary(&mut self, input: &'a UnaryExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Option<Self::Output> {
match input.op {
UnaryOperation::Not => {
self.visitor.assert_type(Type::Boolean, expected, input.span());
self.visit_expression(&input.inner, expected)
UnaryOperation::Abs => {
// Assert integer type only.
self.visitor.assert_int_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::AbsWrapped => {
// Assert integer type only.
self.visitor.assert_int_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::Double => {
// Assert field and group type only.
self.visitor.assert_field_group_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::Inverse => {
// Assert field type only.
self.visitor
.assert_expected_type(destination, Type::Field, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::Negate => {
let prior_negate_state = self.visitor.negate;
self.visitor.negate = true;
let type_ = self.visit_expression(&input.inner, expected);
let type_ = self.visit_expression(&input.receiver, destination);
self.visitor.negate = prior_negate_state;
match type_.as_ref() {
Some(
@ -343,11 +459,27 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
Some(t) => self
.visitor
.handler
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.inner.span()).into()),
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.receiver.span()).into()),
_ => {}
};
type_
}
UnaryOperation::Not => {
// Assert boolean, integer types only.
self.visitor.assert_bool_int_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::Square => {
// Assert field type only.
self.visitor
.assert_expected_type(destination, Type::Field, input.span());
self.visit_expression(&input.receiver, destination)
}
UnaryOperation::SquareRoot => {
// Assert field and scalar types only.
self.visitor.assert_field_scalar_type(destination, input.span());
self.visit_expression(&input.receiver, destination)
}
}
}
@ -372,7 +504,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
match &*input.function {
Expression::Identifier(ident) => {
if let Some(func) = self.visitor.symbol_table.clone().lookup_fn(&ident.name) {
let ret = self.visitor.assert_type(func.output, expected, func.span());
let ret = self.visitor.assert_expected_option(func.output, expected, func.span());
if func.input.len() != input.arguments.len() {
self.visitor.handler.emit_err(

View File

@ -45,6 +45,12 @@ const INT_TYPES: [Type; 10] = [
Type::IntegerType(IntegerType::U128),
];
const MAGNITUDE_TYPES: [Type; 3] = [
Type::IntegerType(IntegerType::U8),
Type::IntegerType(IntegerType::U16),
Type::IntegerType(IntegerType::U32),
];
const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
subset: [Type; S],
additional: [Type; A],
@ -63,14 +69,18 @@ const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
superset
}
const FIELD_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Field]);
const BOOL_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Boolean]);
const FIELD_SCALAR_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES, [Type::Scalar]);
const FIELD_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Field]);
const FIELD_GROUP_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES, [Type::Group]);
const FIELD_GROUP_SCALAR_INT_TYPES: [Type; 13] = create_type_superset(FIELD_GROUP_INT_TYPES, [Type::Scalar]);
const FIELD_GROUP_TYPES: [Type; 2] = [Type::Field, Type::Group];
const FIELD_SCALAR_TYPES: [Type; 2] = [Type::Field, Type::Scalar];
impl<'a> TypeChecker<'a> {
/// Returns a new type checker given a symbol table and error handler.
pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
@ -108,16 +118,29 @@ impl<'a> TypeChecker<'a> {
}
}
/// Returns the given type if it equals the expected type or the expected type is none.
pub(crate) fn assert_type(&mut self, type_: Type, expected: &Option<Type>, span: Span) -> Type {
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
if let Some(expected) = expected {
if &type_ != expected {
if &actual != expected {
self.handler
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
}
}
type_
actual
}
/// Returns the given `expected` type and emits an error if the `actual` type does not match.
/// `span` should be the location of the expected type.
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
if let Some(actual) = actual {
if actual != &expected {
self.handler
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
}
}
expected
}
/// Emits an error to the error handler if the given type is not equal to any of the expected types.
@ -136,14 +159,19 @@ impl<'a> TypeChecker<'a> {
}
}
/// Emits an error to the handler if the given type is not a boolean or an integer.
pub(crate) fn assert_bool_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &BOOL_INT_TYPES, span)
}
/// Emits an error to the handler if the given type is not a field or integer.
pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
}
/// Emits an error to the handler if the given type is not a field, scalar, or integer.
pub(crate) fn assert_field_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_SCALAR_INT_TYPES, span)
/// Emits an error to the handler if the given type is not a field or group.
pub(crate) fn assert_field_group_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_GROUP_TYPES, span)
}
/// Emits an error to the handler if the given type is not a field, group, or integer.
@ -155,4 +183,18 @@ impl<'a> TypeChecker<'a> {
pub(crate) fn assert_field_group_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_GROUP_SCALAR_INT_TYPES, span)
}
/// Emits an error to the handler if the given type is not a field or scalar.
pub(crate) fn assert_field_scalar_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &FIELD_SCALAR_TYPES, span)
}
/// Emits an error to the handler if the given type is not an integer.
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &INT_TYPES, span)
}
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
self.assert_one_of_types(type_, &MAGNITUDE_TYPES, span)
}
}

View File

@ -1,4 +1,3 @@
function main() -> bool {
console.log("hello world");
return true;
function main(a: u8) -> u8 {
return a >> 1u32;
}

View File

@ -366,4 +366,12 @@ create_messages!(
msg: "Expression statements are no longer supported.",
help: None,
}
/// Previously, arbitrary methods were allowed, but not anymore.
@formatted
expr_arbitrary_method_call {
args: (),
msg: "Arbitrary methods calls are not supported. Only special ones are.",
help: None,
}
);

View File

@ -53,6 +53,16 @@ create_messages!(
help: None,
}
/// The method name is known but not supported for the given type.
@formatted
type_method_not_supported {
args: (type_: impl Display, method: impl Display),
msg: format!(
"Type `{type_}` does not support associated method `{method}`",
),
help: None,
}
/// For when the user tries to return a unknown variable.
@formatted
unknown_sym {

View File

@ -16,9 +16,8 @@
use leo_errors::Result;
use std::{fmt, sync::Once};
use colored::Colorize;
use std::{fmt, sync::Once};
use tracing::{event::Event, subscriber::Subscriber};
use tracing_subscriber::{
fmt::{format::*, time::*, FmtContext, FormattedFields},

View File

@ -100,30 +100,94 @@ macro_rules! symbols {
}
symbols! {
// unary operators index 0-7
abs,
abs_wrapped,
double,
inv,
neg,
not,
square,
sqrt,
// binary operators index 8-32
add,
add_wrapped,
and,
div,
div_wrapped,
eq,
ge,
gt,
le,
lt,
mul,
mul_wrapped,
nand,
neq,
nor,
or,
pow,
pow_wrapped,
shl,
shl_wrapped,
shr,
shr_wrapped,
sub,
sub_wrapped,
xor,
// algorithm operator names 33-44
bhp256,
bhp512,
bhp768,
bhp1024,
commit,
hash,
ped64,
ped128,
prf,
psd2,
psd4,
psd8,
// types
address,
AlwaysConst,
array,
assert,
bool,
Class: "class",
context,
constants,
CoreFunction,
console,
Const: "const",
Constant,
Else: "else",
error,
False: "false",
constants,
field,
For: "for",
function,
group,
i8,
i16,
i32,
i64,
i128,
scalar,
string,
u8,
u16,
u32,
u64,
u128,
// values
False: "false",
True: "true",
// general keywords
AlwaysConst,
assert,
Class: "class",
context,
CoreFunction,
console,
Else: "else",
error,
For: "for",
function,
If: "if",
In: "in",
input,
@ -134,19 +198,11 @@ symbols! {
prelude,
Public,
Return: "return",
scalar,
Star: "*",
std,
string,
Struct: "struct",
test,
True: "true",
Type: "type",
u8,
u16,
u32,
u64,
u128,
CONTAINER_PSEUDO_CIRCUIT: "$InputContainer",
REGISTERS_PSEUDO_CIRCUIT: "$InputRegister",
@ -154,11 +210,11 @@ symbols! {
STATE_PSEUDO_CIRCUIT: "$InputState",
STATE_LEAF_PSEUDO_CIRCUIT: "$InputStateLeaf",
// input file
registers,
record,
state,
state_leaf,
public,
private,
}

View File

@ -17,6 +17,8 @@
use crate::config::Config;
use leo_errors::{CliError, Result};
use std::fmt::Write as _;
use colored::Colorize;
use self_update::{backends::github, version::bump_is_greater, Status};
@ -40,7 +42,7 @@ impl Updater {
let mut output = "\nList of available versions\n".to_string();
for release in releases {
output += &format!(" * {}\n", release.version);
let _ = writeln!(output, " * {}", release.version);
}
// Forgo using tracing to list the available versions without a log status.

View File

@ -0,0 +1,13 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/address1.in
*/
function main (x: address) -> bool {
let a: address = aleo1fj982yqchhy973kz7e9jk6er7t6qd6jm9anplnlprem507w6lv9spwvfxx;
let b: bool = x.eq(a);
let c: bool = x.neq(a);
return c;
}

View File

@ -0,0 +1,25 @@
/*
namespace: Compile
expectation: Pass
input_file:
- inputs/false_false.in
- inputs/false_true.in
- inputs/true_false.in
- inputs/true_true.in
*/
function main(a: bool, b: bool) -> bool {
// unary
let h: bool = a.not();
// binary
let l: bool = a.and(b);
let o: bool = a.eq(b);
let v: bool = a.nand(b);
let w: bool = a.neq(b);
let x: bool = a.nor(b);
let y: bool = a.or(b);
let ar: bool = a.xor(b);
return h;
}

View File

@ -0,0 +1,28 @@
/*
namespace: Compile
expectation: Pass
input_file:
- inputs/fields.in
*/
function main(a: field, b: field) -> bool {
// unary
let f: field = a.inv();
let g: field = a.neg();
let i: field = a.square();
let j: field = a.sqrt();
// binary
let k: field = a.add(b);
let m: field = a.div(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: field = a.mul(b);
let w: bool = a.neq(b);
let z: field = a.pow(b);
return w;
}

View File

@ -7,5 +7,5 @@ input_file:
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField ** 2i8 == 1field;
return negOneField ** 2field == 1field;
}

View File

@ -1,11 +0,0 @@
/*
namespace: Compile
expectation: Pass
input_file:
- inputs/fields.in
*/
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField ** 2u8 == 1field;
}

View File

@ -0,0 +1,20 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/three.in
*/
function main(a: group, b: group) -> bool {
// unary
let e: group = a.double();
let g: group = a.neg();
// binary
let j: group = a.add(b);
let o: bool = a.eq(b);
let t: group = a.mul(2scalar);
let q: group = 2scalar.mul(a);
let w: bool = a.neq(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,50 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128) -> bool {
// unary
let c: i128 = a.abs();
let d: i128 = a.abs_wrapped();
let g: i128 = a.neg();
let h: i128 = a.not();
// binary
let j: i128 = a.add(b);
let k: i128 = a.add_wrapped(b);
let l: i128 = a.and(b);
let m: i128 = a.div(b);
let n: i128 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: i128 = a.mul(b);
let u: i128 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: i128 = a.or(b);
let z: i128 = a.pow(2u8);
let aa: i128 = a.pow(2u16);
let ab: i128 = a.pow(2u32);
let ac: i128 = a.pow_wrapped(2u8);
let ad: i128 = a.pow_wrapped(2u16);
let ae: i128 = a.pow_wrapped(2u32);
let af: i128 = a.shl(2u8);
let ag: i128 = a.shl(2u16);
let ah: i128 = a.shl(2u32);
let ai: i128 = a.shl_wrapped(2u8);
let aj: i128 = a.shl_wrapped(2u16);
let ak: i128 = a.shl_wrapped(2u32);
let al: i128 = a.shr(2u8);
let am: i128 = a.shr(2u16);
let an: i128 = a.shr(2u32);
let ao: i128 = a.shr_wrapped(2u8);
let ap: i128 = a.shr_wrapped(2u16);
let aq: i128 = a.shr_wrapped(2u32);
let ar: i128 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a | b == c;
}

View File

@ -1,9 +1,9 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/pow.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i128, b: i128, c: i128) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,50 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16) -> bool {
// unary
let c: i16 = a.abs();
let d: i16 = a.abs_wrapped();
let g: i16 = a.neg();
let h: i16 = a.not();
// binary
let j: i16 = a.add(b);
let k: i16 = a.add_wrapped(b);
let l: i16 = a.and(b);
let m: i16 = a.div(b);
let n: i16 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: i16 = a.mul(b);
let u: i16 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: i16 = a.or(b);
let z: i16 = a.pow(2u8);
let aa: i16 = a.pow(2u16);
let ab: i16 = a.pow(2u32);
let ac: i16 = a.pow_wrapped(2u8);
let ad: i16 = a.pow_wrapped(2u16);
let ae: i16 = a.pow_wrapped(2u32);
let af: i16 = a.shl(2u8);
let ag: i16 = a.shl(2u16);
let ah: i16 = a.shl(2u32);
let ai: i16 = a.shl_wrapped(2u8);
let aj: i16 = a.shl_wrapped(2u16);
let ak: i16 = a.shl_wrapped(2u32);
let al: i16 = a.shr(2u8);
let am: i16 = a.shr(2u16);
let an: i16 = a.shr(2u32);
let ao: i16 = a.shr_wrapped(2u8);
let ap: i16 = a.shr_wrapped(2u16);
let aq: i16 = a.shr_wrapped(2u32);
let ar: i16 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a | b == c;
}

View File

@ -1,9 +1,9 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/pow.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i16, b: i16, c: i16) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,50 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32) -> bool {
// unary
let c: i32 = a.abs();
let d: i32 = a.abs_wrapped();
let g: i32 = a.neg();
let h: i32 = a.not();
// binary
let j: i32 = a.add(b);
let k: i32 = a.add_wrapped(b);
let l: i32 = a.and(b);
let m: i32 = a.div(b);
let n: i32 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: i32 = a.mul(b);
let u: i32 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: i32 = a.or(b);
let z: i32 = a.pow(2u8);
let aa: i32 = a.pow(2u16);
let ab: i32 = a.pow(2u32);
let ac: i32 = a.pow_wrapped(2u8);
let ad: i32 = a.pow_wrapped(2u16);
let ae: i32 = a.pow_wrapped(2u32);
let af: i32 = a.shl(2u8);
let ag: i32 = a.shl(2u16);
let ah: i32 = a.shl(2u32);
let ai: i32 = a.shl_wrapped(2u8);
let aj: i32 = a.shl_wrapped(2u16);
let ak: i32 = a.shl_wrapped(2u32);
let al: i32 = a.shr(2u8);
let am: i32 = a.shr(2u16);
let an: i32 = a.shr(2u32);
let ao: i32 = a.shr_wrapped(2u8);
let ap: i32 = a.shr_wrapped(2u16);
let aq: i32 = a.shr_wrapped(2u32);
let ar: i32 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a | b == c;
}

View File

@ -1,9 +1,9 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/pow.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i32, b: i32, c: i32) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,50 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64) -> bool {
// unary
let c: i64 = a.abs();
let d: i64 = a.abs_wrapped();
let g: i64 = a.neg();
let h: i64 = a.not();
// binary
let j: i64 = a.add(b);
let k: i64 = a.add_wrapped(b);
let l: i64 = a.and(b);
let m: i64 = a.div(b);
let n: i64 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: i64 = a.mul(b);
let u: i64 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: i64 = a.or(b);
let z: i64 = a.pow(2u8);
let aa: i64 = a.pow(2u16);
let ab: i64 = a.pow(2u32);
let ac: i64 = a.pow_wrapped(2u8);
let ad: i64 = a.pow_wrapped(2u16);
let ae: i64 = a.pow_wrapped(2u32);
let af: i64 = a.shl(2u8);
let ag: i64 = a.shl(2u16);
let ah: i64 = a.shl(2u32);
let ai: i64 = a.shl_wrapped(2u8);
let aj: i64 = a.shl_wrapped(2u16);
let ak: i64 = a.shl_wrapped(2u32);
let al: i64 = a.shr(2u8);
let am: i64 = a.shr(2u16);
let an: i64 = a.shr(2u32);
let ao: i64 = a.shr_wrapped(2u8);
let ap: i64 = a.shr_wrapped(2u16);
let aq: i64 = a.shr_wrapped(2u32);
let ar: i64 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a | b == c;
}

View File

@ -1,9 +1,9 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/pow.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i64, b: i64, c: i64) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,50 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8) -> bool {
// unary
let c: i8 = a.abs();
let d: i8 = a.abs_wrapped();
let g: i8 = a.neg();
let h: i8 = a.not();
// binary
let j: i8 = a.add(b);
let k: i8 = a.add_wrapped(b);
let l: i8 = a.and(b);
let m: i8 = a.div(b);
let n: i8 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: i8 = a.mul(b);
let u: i8 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: i8 = a.or(b);
let z: i8 = a.pow(2u8);
let aa: i8 = a.pow(2u16);
let ab: i8 = a.pow(2u32);
let ac: i8 = a.pow_wrapped(2u8);
let ad: i8 = a.pow_wrapped(2u16);
let ae: i8 = a.pow_wrapped(2u32);
let af: i8 = a.shl(2u8);
let ag: i8 = a.shl(2u16);
let ah: i8 = a.shl(2u32);
let ai: i8 = a.shl_wrapped(2u8);
let aj: i8 = a.shl_wrapped(2u16);
let ak: i8 = a.shl_wrapped(2u32);
let al: i8 = a.shr(2u8);
let am: i8 = a.shr(2u16);
let an: i8 = a.shr(2u32);
let ao: i8 = a.shr_wrapped(2u8);
let ap: i8 = a.shr_wrapped(2u16);
let aq: i8 = a.shr_wrapped(2u32);
let ar: i8 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a | b == c;
}

View File

@ -1,9 +1,9 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/pow.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: i8, b: i8, c: i8) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,49 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128) -> bool {
// unary
let c: u128 = a.abs();
let d: u128 = a.abs_wrapped();
let h: u128 = a.not();
// binary
let j: u128 = a.add(b);
let k: u128 = a.add_wrapped(b);
let l: u128 = a.and(b);
let m: u128 = a.div(b);
let n: u128 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: u128 = a.mul(b);
let u: u128 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: u128 = a.or(b);
let z: u128 = a.pow(2u8);
let aa: u128 = a.pow(2u16);
let ab: u128 = a.pow(2u32);
let ac: u128 = a.pow_wrapped(2u8);
let ad: u128 = a.pow_wrapped(2u16);
let ae: u128 = a.pow_wrapped(2u32);
let af: u128 = a.shl(2u8);
let ag: u128 = a.shl(2u16);
let ah: u128 = a.shl(2u32);
let ai: u128 = a.shl_wrapped(2u8);
let aj: u128 = a.shl_wrapped(2u16);
let ak: u128 = a.shl_wrapped(2u32);
let al: u128 = a.shr(2u8);
let am: u128 = a.shr(2u16);
let an: u128 = a.shr(2u32);
let ao: u128 = a.shr_wrapped(2u8);
let ap: u128 = a.shr_wrapped(2u16);
let aq: u128 = a.shr_wrapped(2u32);
let ar: u128 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a | b == c;
}

View File

@ -1,12 +1,10 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/pow.in
# This test might take to long to fully compile.
# If necessary we could move it to disabled_tests.
# The exponent must be u8, u16, or u32
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u128, b: u128, c: u128) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,55 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16) -> bool {
// unary
let c: u16 = a.abs();
let d: u16 = a.abs_wrapped();
let h: u16 = a.not();
// binary
let j: u16 = a.add(b);
let k: u16 = a.add_wrapped(b);
let l: u16 = a.and(b);
let m: u16 = a.div(b);
let n: u16 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: u16 = a.mul(b);
let u: u16 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: u16 = a.or(b);
let z: u16 = a.pow(2u8);
let aa: u16 = a.pow(b);
let ab: u16 = a.pow(2u32);
let ac: u16 = a.pow_wrapped(2u8);
let ad: u16 = a.pow_wrapped(b);
let ae: u16 = a.pow_wrapped(2u32);
let af: u16 = a.shl(2u8);
let ag: u16 = a.shl(b);
let ah: u16 = a.shl(2u32);
let ai: u16 = a.shl_wrapped(2u8);
let aj: u16 = a.shl_wrapped(b);
let ak: u16 = a.shl_wrapped(2u32);
let al: u16 = a.shr(2u8);
let am: u16 = a.shr(b);
let an: u16 = a.shr(2u32);
let ao: u16 = a.shr_wrapped(2u8);
let ap: u16 = a.shr_wrapped(b);
let aq: u16 = a.shr_wrapped(2u32);
let ar: u16 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a | b == c;
}

View File

@ -5,5 +5,5 @@ input_file: inputs/pow.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a ** b == c;
return a ** 2u8 == a ** b && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a << 2u8 == a << b && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a >> 2u8 == a >> b && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u16, b: u16, c: u16) -> bool {
return a ^ 2u8 == a ^ b && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,55 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32) -> bool {
// unary
let c: u32 = a.abs();
let d: u32 = a.abs_wrapped();
let h: u32 = a.not();
// binary
let j: u32 = a.add(b);
let k: u32 = a.add_wrapped(b);
let l: u32 = a.and(b);
let m: u32 = a.div(b);
let n: u32 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: u32 = a.mul(b);
let u: u32 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: u32 = a.or(b);
let z: u32 = a.pow(2u8);
let aa: u32 = a.pow(2u16);
let ab: u32 = a.pow(b);
let ac: u32 = a.pow_wrapped(2u8);
let ad: u32 = a.pow_wrapped(2u16);
let ae: u32 = a.pow_wrapped(b);
let af: u32 = a.shl(2u8);
let ag: u32 = a.shl(2u16);
let ah: u32 = a.shl(b);
let ai: u32 = a.shl_wrapped(2u8);
let aj: u32 = a.shl_wrapped(2u16);
let ak: u32 = a.shl_wrapped(b);
let al: u32 = a.shr(2u8);
let am: u32 = a.shr(2u16);
let an: u32 = a.shr(b);
let ao: u32 = a.shr_wrapped(2u8);
let ap: u32 = a.shr_wrapped(2u16);
let aq: u32 = a.shr_wrapped(b);
let ar: u32 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a | b == c;
}

View File

@ -8,5 +8,5 @@ input_file: inputs/pow.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** b == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a << 2u8 == a << 2u16 && a << b == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a >> 2u8 == a >> 2u16 && a >> b == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u32, b: u32, c: u32) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ b == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,49 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64) -> bool {
// unary
let c: u64 = a.abs();
let d: u64 = a.abs_wrapped();
let h: u64 = a.not();
// binary
let j: u64 = a.add(b);
let k: u64 = a.add_wrapped(b);
let l: u64 = a.and(b);
let m: u64 = a.div(b);
let n: u64 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: u64 = a.mul(b);
let u: u64 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: u64 = a.or(b);
let z: u64 = a.pow(2u8);
let aa: u64 = a.pow(2u16);
let ab: u64 = a.pow(2u32);
let ac: u64 = a.pow_wrapped(2u8);
let ad: u64 = a.pow_wrapped(2u16);
let ae: u64 = a.pow_wrapped(2u32);
let af: u64 = a.shl(2u8);
let ag: u64 = a.shl(2u16);
let ah: u64 = a.shl(2u32);
let ai: u64 = a.shl_wrapped(2u8);
let aj: u64 = a.shl_wrapped(2u16);
let ak: u64 = a.shl_wrapped(2u32);
let al: u64 = a.shr(2u8);
let am: u64 = a.shr(2u16);
let an: u64 = a.shr(2u32);
let ao: u64 = a.shr_wrapped(2u8);
let ap: u64 = a.shr_wrapped(2u16);
let aq: u64 = a.shr_wrapped(2u32);
let ar: u64 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a | b == c;
}

View File

@ -3,10 +3,9 @@ namespace: Compile
expectation: Pass
input_file: inputs/pow.in
# This test might take to long to fully compile.
# If necessary we could move it to disabled_tests.
# The exponent must be u8, u16, or u32
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a ** b == c;
return a ** 2u8 == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a << 2u8 == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a >> 2u8 == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u64, b: u64, c: u64) -> bool {
return a ^ 2u8 == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a & b == c;
}

View File

@ -0,0 +1,49 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8) -> bool {
// unary
let c: u8 = a.abs();
let d: u8 = a.abs_wrapped();
let h: u8 = a.not();
// binary
let j: u8 = a.add(b);
let k: u8 = a.add_wrapped(b);
let l: u8 = a.and(b);
let m: u8 = a.div(b);
let n: u8 = a.div_wrapped(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: u8 = a.mul(b);
let u: u8 = a.mul_wrapped(b);
let w: bool = a.neq(b);
let y: u8 = a.or(b);
let z: u8 = a.pow(b);
let aa: u8 = a.pow(2u16);
let ab: u8 = a.pow(2u32);
let ac: u8 = a.pow_wrapped(b);
let ad: u8 = a.pow_wrapped(2u16);
let ae: u8 = a.pow_wrapped(2u32);
let af: u8 = a.shl(b);
let ag: u8 = a.shl(2u16);
let ah: u8 = a.shl(2u32);
let ai: u8 = a.shl_wrapped(b);
let aj: u8 = a.shl_wrapped(2u16);
let ak: u8 = a.shl_wrapped(2u32);
let al: u8 = a.shr(b);
let am: u8 = a.shr(2u16);
let an: u8 = a.shr(2u32);
let ao: u8 = a.shr_wrapped(b);
let ap: u8 = a.shr_wrapped(2u16);
let aq: u8 = a.shr_wrapped(2u32);
let ar: u8 = a.xor(b);
return a == b;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a | b == c;
}

View File

@ -5,5 +5,5 @@ input_file: inputs/pow.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a ** b == c;
return a ** b == a ** 2u16 && a ** 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a << b == a << 2u16 && a << 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a >> b == a >> 2u16 && a >> 2u32 == c;
}

View File

@ -0,0 +1,9 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/add.in
*/
function main(a: u8, b: u8, c: u8) -> bool {
return a ^ b == a ^ 2u16 && a ^ 2u32 == c;
}

View File

@ -0,0 +1,24 @@
/*
namespace: Compile
expectation: Pass
input_file:
- inputs/scalars.in
*/
function main(a: scalar, b: scalar) -> bool {
// unary
let i: scalar = a.sqrt();
// binary
let j: scalar = a.add(b);
let o: bool = a.eq(b);
let p: bool = a.ge(b);
let q: bool = a.gt(b);
let r: bool = a.le(b);
let s: bool = a.lt(b);
let t: group = 2group.mul(b);
let u: group = a.mul(2group);
let w: bool = a.neq(b);
return a == b;
}

View File

@ -1,6 +1,6 @@
/*
namespace: Compile
expectation: Fail
expectation: Pass
input_file: inputs/i8.in
*/

View File

@ -0,0 +1,8 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: ed65ff9337fc5a00cd28d780a985bcb05de7d0e5fe02b555774984552f0c14e8
initial_ast: 64b4179c6d21058f1e4a91826cd91364f7011e35e5e30a1d9dbc899ec3b500df
symbol_table: b736692dc7bdc91c5a808a20a3965f4c8ed2c46c212696d33fc6dd4cfc9a5844

View File

@ -5,4 +5,4 @@ outputs:
- output:
- initial_input_ast: c7315faf1ac3ceeb90260e64e4a411a27a8aa732892a64c15f49e81adf464beb
initial_ast: 767d8228dd9818cb115e7369cec91352dd406008981487380e863deb06dc11a0
symbol_table: e8029086f943767e4f98014b3991bff8336cb6472c2d2dc3d51b4b13e5c72ea5
symbol_table: a712053d471b6165809fc2b4f717282ea5590a2cfaeae8a630c8a3250478d179

View File

@ -6,4 +6,4 @@ outputs:
- initial_input_ast: dc6b4b00185dd6c1f2b83a1bfae619c1d6e3f68ac0f1d3d87ae3bd0ed5caf083
- initial_input_ast: 73a38568160c3d2be402043d04ccdc2290abe27647bc81c4bd50367834c206cf
initial_ast: 31f3fdca173acafc69b0975e91e891bbb27bf6d63bdc986c86b4d22c70d928cc
symbol_table: 25f09247dfa86534ff321b8e1b2ca1666c92751d37a611d62e56b8cfac96261d
symbol_table: 18395a136ea969d319cc4c12c59bb7a590a1b11339375240700d7c87f26b1d5d

Some files were not shown because too many files have changed in this diff Show More