Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(experimental): Add comptime keyword #4840

Merged
merged 24 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions aztec_macros/src/utils/ast_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub fn mutable_assignment(name: &str, assigned_to: Expression) -> Statement {
pattern: mutable(name),
r#type: make_type(UnresolvedTypeData::Unspecified),
expression: assigned_to,
comptime: false,
attributes: vec![],
}))
}
Expand All @@ -90,6 +91,7 @@ pub fn assignment_with_type(
pattern: pattern(name),
r#type: make_type(typ),
expression: assigned_to,
comptime: false,
attributes: vec![],
}))
}
Expand Down
53 changes: 36 additions & 17 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub enum StatementKind {
For(ForLoopStatement),
Break,
Continue,
/// This statement should be executed at compile-time
Comptime(Box<StatementKind>),
// This is an expression with a trailing semi-colon
Semi(Expression),
// This statement is the result of a recovered parse error.
Expand All @@ -47,6 +49,19 @@ pub enum StatementKind {
}

impl Statement {
pub fn add_semicolon(
mut self,
semi: Option<Token>,
span: Span,
last_statement_in_block: bool,
emit_error: &mut dyn FnMut(ParserError),
) -> Self {
self.kind = self.kind.add_semicolon(semi, span, last_statement_in_block, emit_error);
self
}
}

impl StatementKind {
pub fn add_semicolon(
self,
semi: Option<Token>,
Expand All @@ -57,7 +72,7 @@ impl Statement {
let missing_semicolon =
ParserError::with_reason(ParserErrorReason::MissingSeparatingSemi, span);

let kind = match self.kind {
match self {
StatementKind::Let(_)
| StatementKind::Constrain(_)
| StatementKind::Assign(_)
Expand All @@ -69,10 +84,15 @@ impl Statement {
if semi.is_none() {
emit_error(missing_semicolon);
}
self.kind
self
}
StatementKind::Comptime(mut statement) => {
*statement =
statement.add_semicolon(semi, span, last_statement_in_block, emit_error);
StatementKind::Comptime(statement)
}
// A semicolon on a for loop is optional and does nothing
StatementKind::For(_) => self.kind,
StatementKind::For(_) => self,

StatementKind::Expression(expr) => {
match (&expr.kind, semi, last_statement_in_block) {
Expand All @@ -92,9 +112,7 @@ impl Statement {
(_, None, true) => StatementKind::Expression(expr),
}
}
};

Statement { kind, span: self.span }
}
}
}

Expand All @@ -108,7 +126,13 @@ impl StatementKind {
pub fn new_let(
((pattern, r#type), expression): ((Pattern, UnresolvedType), Expression),
) -> StatementKind {
StatementKind::Let(LetStatement { pattern, r#type, expression, attributes: vec![] })
StatementKind::Let(LetStatement {
pattern,
r#type,
expression,
comptime: false,
attributes: vec![],
})
}

/// Create a Statement::Assign value, desugaring any combined operators like += if needed.
Expand Down Expand Up @@ -407,17 +431,9 @@ pub struct LetStatement {
pub r#type: UnresolvedType,
pub expression: Expression,
pub attributes: Vec<SecondaryAttribute>,
}

impl LetStatement {
pub fn new_let(
(((pattern, r#type), expression), attributes): (
((Pattern, UnresolvedType), Expression),
Vec<SecondaryAttribute>,
),
) -> LetStatement {
LetStatement { pattern, r#type, expression, attributes }
}
// True if this should only be run during compile-time
pub comptime: bool,
}

#[derive(Debug, PartialEq, Eq, Clone)]
Expand Down Expand Up @@ -573,6 +589,7 @@ impl ForRange {
pattern: Pattern::Identifier(array_ident.clone()),
r#type: UnresolvedType::unspecified(),
expression: array,
comptime: false,
attributes: vec![],
}),
span: array_span,
Expand Down Expand Up @@ -616,6 +633,7 @@ impl ForRange {
pattern: Pattern::Identifier(identifier),
r#type: UnresolvedType::unspecified(),
expression: Expression::new(loop_element, array_span),
comptime: false,
attributes: vec![],
}),
span: array_span,
Expand Down Expand Up @@ -666,6 +684,7 @@ impl Display for StatementKind {
StatementKind::For(for_loop) => for_loop.fmt(f),
StatementKind::Break => write!(f, "break"),
StatementKind::Continue => write!(f, "continue"),
StatementKind::Comptime(statement) => write!(f, "comptime {statement}"),
StatementKind::Semi(semi) => write!(f, "{semi};"),
StatementKind::Error => write!(f, "Error"),
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_frontend/src/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ impl DebugInstrumenter {
pattern: ast::Pattern::Identifier(ident("__debug_expr", ret_expr.span)),
r#type: ast::UnresolvedType::unspecified(),
expression: ret_expr.clone(),
comptime: false,
attributes: vec![],
}),
span: ret_expr.span,
Expand Down Expand Up @@ -243,6 +244,7 @@ impl DebugInstrumenter {
kind: ast::StatementKind::Let(ast::LetStatement {
pattern: ast::Pattern::Tuple(vars_pattern, let_stmt.pattern.span()),
r#type: ast::UnresolvedType::unspecified(),
comptime: false,
expression: ast::Expression {
kind: ast::ExpressionKind::Block(ast::BlockExpression {
statements: block_stmts,
Expand Down Expand Up @@ -275,6 +277,7 @@ impl DebugInstrumenter {
pattern: ast::Pattern::Identifier(ident("__debug_expr", assign_stmt.expression.span)),
r#type: ast::UnresolvedType::unspecified(),
expression: assign_stmt.expression.clone(),
comptime: false,
attributes: vec![],
});
let expression_span = assign_stmt.expression.span;
Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/hir_to_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl StmtId {
pattern,
r#type,
expression,
comptime: false,
attributes: Vec::new(),
})
}
Expand Down Expand Up @@ -64,6 +65,9 @@ impl StmtId {
HirStatement::Expression(expr) => StatementKind::Expression(expr.to_ast(interner)),
HirStatement::Semi(expr) => StatementKind::Semi(expr.to_ast(interner)),
HirStatement::Error => StatementKind::Error,
HirStatement::Comptime(statement) => {
StatementKind::Comptime(Box::new(statement.to_ast(interner).kind))
}
};

Statement { kind, span }
Expand Down
13 changes: 13 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub(crate) struct Interpreter<'interner> {
changed_globally: bool,

in_loop: bool,

/// True if we're currently in a compile-time context.
/// If this is false code is skipped over instead of executed.
in_comptime_context: bool,
}

#[allow(unused)]
Expand Down Expand Up @@ -121,6 +125,7 @@ impl<'a> Interpreter<'a> {
changed_functions: HashSet::default(),
changed_globally: false,
in_loop: false,
in_comptime_context: false,
}
}

Expand Down Expand Up @@ -1074,6 +1079,7 @@ impl<'a> Interpreter<'a> {
HirStatement::Break => self.evaluate_break(),
HirStatement::Continue => self.evaluate_continue(),
HirStatement::Expression(expression) => self.evaluate(expression),
HirStatement::Comptime(statement) => self.evaluate_comptime(statement),
HirStatement::Semi(expression) => {
self.evaluate(expression)?;
Ok(Value::Unit)
Expand Down Expand Up @@ -1246,6 +1252,13 @@ impl<'a> Interpreter<'a> {
Err(InterpreterError::ContinueNotInLoop)
}
}

fn evaluate_comptime(&mut self, statement: StmtId) -> IResult<Value> {
let was_in_comptime = std::mem::replace(&mut self.in_comptime_context, true);
let result = self.evaluate_statement(statement);
self.in_comptime_context = was_in_comptime;
result
}
}

impl Value {
Expand Down
4 changes: 4 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,10 @@ impl<'a> Resolver<'a> {
HirStatement::Continue
}
StatementKind::Error => HirStatement::Error,
StatementKind::Comptime(statement) => {
let statement = self.resolve_stmt(*statement, span);
HirStatement::Comptime(self.interner.push_stmt(statement))
}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/hir/type_check/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl<'interner> TypeChecker<'interner> {
HirStatement::Constrain(constrain_stmt) => self.check_constrain_stmt(constrain_stmt),
HirStatement::Assign(assign_stmt) => self.check_assign_stmt(assign_stmt, stmt_id),
HirStatement::For(for_loop) => self.check_for_loop(for_loop),
HirStatement::Comptime(statement) => return self.check_statement(&statement),
HirStatement::Break | HirStatement::Continue | HirStatement::Error => (),
}
Type::Unit
Expand Down
3 changes: 2 additions & 1 deletion compiler/noirc_frontend/src/hir_def/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::expr::HirIdent;
use crate::macros_api::SecondaryAttribute;
use crate::node_interner::ExprId;
use crate::node_interner::{ExprId, StmtId};
use crate::{Ident, Type};
use fm::FileId;
use noirc_errors::{Location, Span};
Expand All @@ -19,6 +19,7 @@ pub enum HirStatement {
Continue,
Expression(ExprId),
Semi(ExprId),
Comptime(StmtId),
Error,
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ impl<'interner> Monomorphizer<'interner> {
HirStatement::Break => Ok(ast::Expression::Break),
HirStatement::Continue => Ok(ast::Expression::Continue),
HirStatement::Error => unreachable!(),

// All `comptime` statements & expressions should be removed before runtime.
HirStatement::Comptime(_) => unreachable!("comptime statement in runtime code"),
}
}

Expand Down
Loading
Loading