From 1b7601804fefd755ce32559dba585ea163832f59 Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Mon, 26 Aug 2024 18:50:45 +0800 Subject: [PATCH 1/7] Parse HyperTransition syntax --- src/compiler/abepi.rs | 14 +++++ src/compiler/compiler.rs | 95 ++++++++++++++++++------------- src/compiler/semantic/analyser.rs | 7 +++ src/compiler/setup_inter.rs | 1 + src/interpreter/mod.rs | 1 + src/parser/ast/statement.rs | 25 +++++++- src/parser/build.rs | 25 -------- src/parser/chiquito.lalrpop | 11 +++- 8 files changed, 109 insertions(+), 70 deletions(-) diff --git a/src/compiler/abepi.rs b/src/compiler/abepi.rs index ceac8789..caa11804 100644 --- a/src/compiler/abepi.rs +++ b/src/compiler/abepi.rs @@ -65,6 +65,9 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU Statement::Transition(dsym, id, stmt) => { self.compiler_statement_transition(dsym, id, *stmt) } + Statement::HyperTransition(dsym, ids, machine, exprs, state) => { + self.compiler_statement_hyper_transition(dsym, ids, machine, exprs, state) + } _ => vec![], } } @@ -420,6 +423,17 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU result } + + fn compiler_statement_hyper_transition( + &self, + _dsym: DebugSymRef, + _ids: Vec, + _machine: V, + _exprs: Vec>, + _state: V, + ) -> Vec> { + todo!("Compile expressions?") + } } fn flatten_bin_op( diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 9a3c5584..27ee0b39 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -558,57 +558,22 @@ mod test { use crate::{ compiler::{compile, compile_file, compile_legacy}, - parser::ast::debug_sym_factory::DebugSymRefFactory, + parser::{ast::debug_sym_factory::DebugSymRefFactory, lang::TLDeclsParser}, wit_gen::TraceGenerator, }; use super::Config; - // TODO rewrite the test after machines are able to call other machines + // TODO improve the test for HyperTransition #[test] fn test_compiler_fibo_multiple_machines() { // Source code containing two machines let circuit = " - machine fibo1 (signal n) (signal b: field) { - // n and be are created automatically as shared - // signals - signal a: field, i; - - // there is always a state called initial - // input signals get bound to the signal - // in the initial state (first instance) - state initial { - signal c; - - i, a, b, c <== 1, 1, 1, 2; - - -> middle { - i', a', b', n' <== i + 1, b, c, n; - } - } - - state middle { - signal c; - - c <== a + b; - - if i + 1 == n { - -> final { - i', b', n' <== i + 1, c, n; - } - } else { - -> middle { - i', a', b', n' <== i + 1, b, c, n; - } - } - } - - // There is always a state called final. - // Output signals get automatically bound to the signals - // with the same name in the final step (last instance). - // This state can be implicit if there are no constraints in it. + machine caller (signal n) (signal b: field) { + signal b_1: field; + b_1' <== fibo(n) -> final; } - machine fibo2 (signal n) (signal b: field) { + machine fibo (signal n) (signal b: field) { // n and be are created automatically as shared // signals signal a: field, i; @@ -839,4 +804,52 @@ mod test { r#"[SemErr { msg: "use of undeclared variable c", dsym: test/circuit_error.chiquito:24:39 }, SemErr { msg: "use of undeclared variable c", dsym: test/circuit_error.chiquito:28:46 }]"# ) } + + #[test] + fn test_parse_hyper_transition() { + let circuit = " + machine caller (signal n) (signal b: field) { + a', b, c' <== fibo(d, e, f + g) -> final; + } + "; + + let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); + let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); + + assert!(result.is_ok()); + + // Wrong transition operator + let circuit = " + machine caller (signal n) (signal b: field) { + a', b, c' <== fibo(d, e, f + g) --> final; + } + "; + + let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); + let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); + + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!( + err.to_string(), + "Unrecognized token `-` found at 99:100\nExpected one of \"->\"" + ); + + // No transition + let circuit = " + machine caller (signal n) (signal b: field) { + a', b, c' <== fibo(d, e, f + g); + } + "; + + let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); + let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); + + assert!(result.is_err()); + let err = result.err().unwrap(); + assert_eq!( + err.to_string(), + "Unrecognized token `;` found at 98:99\nExpected one of \"->\"" + ); + } } diff --git a/src/compiler/semantic/analyser.rs b/src/compiler/semantic/analyser.rs index 3664608d..1314b89e 100644 --- a/src/compiler/semantic/analyser.rs +++ b/src/compiler/semantic/analyser.rs @@ -272,6 +272,13 @@ impl Analyser { Statement::SignalDecl(_, _) => {} Statement::WGVarDecl(_, _) => {} + Statement::HyperTransition(_, ids, _machine, exprs, _state) => { + // TODO analyze machine? analyze state? + exprs + .into_iter() + .for_each(|expr| self.analyse_expression(expr)); + self.collect_id_usages(&ids); + } } } diff --git a/src/compiler/setup_inter.rs b/src/compiler/setup_inter.rs index 9b2b3e24..8434bae9 100644 --- a/src/compiler/setup_inter.rs +++ b/src/compiler/setup_inter.rs @@ -250,6 +250,7 @@ impl SetupInterpreter { SignalAssignment(_, _, _) | WGAssignment(_, _, _) => vec![], SignalDecl(_, _) | WGVarDecl(_, _) => vec![], + HyperTransition(_, _, _, _, _) => todo!(), }; self.add_poly_constraints(result.into_iter().map(|cr| cr.anti_booly).collect()); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 7cd05010..6c98822e 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -206,6 +206,7 @@ impl<'a, F: Field + Hash> Interpreter<'a, F> { Block(_, stmts) => self.exec_step_block(stmts), Assert(_, _) => Ok(None), StateDecl(_, _, _) => Ok(None), + HyperTransition(_, _, _, _, _) => Ok(None), // TODO execute transition? } } diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index 1d7e9b7f..2534d598 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -31,10 +31,22 @@ pub enum Statement { WGVarDecl(DebugSymRef, Vec>), // var x; StateDecl(DebugSymRef, V, Box>), // state x { y } - + /// Transition to another state. Transition(DebugSymRef, V, Box>), // -> x { y } Block(DebugSymRef, Vec>), // { x } + /// Call into another machine with assertion and subsequent transition to another + /// state: + /// ```no_run + /// id_1', id_2' <== machine_id(expr1, expr2 + expr3) -> state_id; + /// ``` + /// Tuple values: + /// - debug symbol reference; + /// - assigned/asserted ids vector; + /// - machine ID; + /// - call argument expressions vector; + /// - next state ID. + HyperTransition(DebugSymRef, Vec, V, Vec>, V), } impl Debug for Statement { @@ -84,6 +96,16 @@ impl Debug for Statement { .join(" ") ) } + Statement::HyperTransition(_, ids, machine, exprs, state) => { + write!( + f, + "{:?} <== {} ({:?}) --> {:?};", + ids, + machine.name(), + exprs, + state + ) + } } } } @@ -102,6 +124,7 @@ impl Statement { Statement::StateDecl(dsym, _, _) => dsym.clone(), Statement::Transition(dsym, _, _) => dsym.clone(), Statement::Block(dsym, _) => dsym.clone(), + Statement::HyperTransition(dsym, _, _, _, _) => dsym.clone(), } } } diff --git a/src/parser/build.rs b/src/parser/build.rs index d832991d..03348fd8 100644 --- a/src/parser/build.rs +++ b/src/parser/build.rs @@ -1,5 +1,3 @@ -use num_bigint::BigInt; - use super::ast::{expression::Expression, statement::Statement, DebugSymRef, Identifier}; pub fn build_bin_op, F, V>( @@ -63,26 +61,3 @@ pub fn build_transition( ) -> Statement { Statement::Transition(dsym, id, Box::new(block)) } - -pub fn add_dsym( - dsym: DebugSymRef, - stmt: Statement, -) -> Statement { - match stmt { - Statement::Assert(_, expr) => Statement::Assert(dsym, expr), - Statement::SignalAssignment(_, ids, exprs) => Statement::SignalAssignment(dsym, ids, exprs), - Statement::SignalAssignmentAssert(_, ids, exprs) => { - Statement::SignalAssignmentAssert(dsym, ids, exprs) - } - Statement::WGAssignment(_, ids, exprs) => Statement::WGAssignment(dsym, ids, exprs), - Statement::StateDecl(_, id, block) => Statement::StateDecl(dsym, id, block), - Statement::IfThen(_, cond, then_block) => Statement::IfThen(dsym, cond, then_block), - Statement::IfThenElse(_, cond, then_block, else_block) => { - Statement::IfThenElse(dsym, cond, then_block, else_block) - } - Statement::Block(_, stmts) => Statement::Block(dsym, stmts), - Statement::SignalDecl(_, ids) => Statement::SignalDecl(dsym, ids), - Statement::WGVarDecl(_, ids) => Statement::WGVarDecl(dsym, ids), - Statement::Transition(_, id, stmt) => Statement::Transition(dsym, id, stmt), - } -} diff --git a/src/parser/chiquito.lalrpop b/src/parser/chiquito.lalrpop index b8fb582c..35c2d04a 100644 --- a/src/parser/chiquito.lalrpop +++ b/src/parser/chiquito.lalrpop @@ -37,9 +37,9 @@ pub Statements: Vec> = { } ParseStatement: Statement = { - ";" => add_dsym(dsym_factory.create(l,r), s), - => add_dsym(dsym_factory.create(l,r), s), - => add_dsym(dsym_factory.create(l,r), s), + ";" => s, + => s, + => s, } StatementType: Statement = { @@ -53,6 +53,7 @@ StatementType: Statement = { ParseWGVarDecl, ParseTransitionSimple, ParseTransition, + HyperTransition } AssertEq: Statement = { @@ -111,6 +112,10 @@ ParseTransition: Statement = { "->" => build_transition(dsym_factory.create(l,r), id, block), } +HyperTransition: Statement = { + "<==" "(" ")" "->" => Statement::HyperTransition(dsym_factory.create(l,r), ids, machine, es, st), +} + ParseSignalDecl: Statement = { "signal" => Statement::SignalDecl(dsym_factory.create(l,r), ids), } From 7d8a13bf2b7f7fa221d17f4163b51681c1bf4dcc Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Mon, 26 Aug 2024 19:03:58 +0800 Subject: [PATCH 2/7] Fix doc --- src/parser/ast/statement.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index 2534d598..a297c090 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -36,10 +36,7 @@ pub enum Statement { Block(DebugSymRef, Vec>), // { x } /// Call into another machine with assertion and subsequent transition to another - /// state: - /// ```no_run - /// id_1', id_2' <== machine_id(expr1, expr2 + expr3) -> state_id; - /// ``` + /// state. /// Tuple values: /// - debug symbol reference; /// - assigned/asserted ids vector; From eef6836e5f3aa13a0378e504803e0124bfeeeeee Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Mon, 26 Aug 2024 19:47:09 +0800 Subject: [PATCH 3/7] Separate `Call` statement type, parse `HyperTransition` variant with curly braces --- src/compiler/abepi.rs | 8 +++----- src/compiler/compiler.rs | 18 +++++++----------- src/compiler/semantic/analyser.rs | 12 ++++++++---- src/compiler/setup_inter.rs | 3 ++- src/interpreter/mod.rs | 3 ++- src/parser/ast/statement.rs | 30 ++++++++++++++++-------------- src/parser/build.rs | 8 ++++++++ src/parser/chiquito.lalrpop | 9 +++++++-- 8 files changed, 53 insertions(+), 38 deletions(-) diff --git a/src/compiler/abepi.rs b/src/compiler/abepi.rs index caa11804..b58685ae 100644 --- a/src/compiler/abepi.rs +++ b/src/compiler/abepi.rs @@ -65,8 +65,8 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU Statement::Transition(dsym, id, stmt) => { self.compiler_statement_transition(dsym, id, *stmt) } - Statement::HyperTransition(dsym, ids, machine, exprs, state) => { - self.compiler_statement_hyper_transition(dsym, ids, machine, exprs, state) + Statement::HyperTransition(dsym, state, call) => { + self.compiler_statement_hyper_transition(dsym, state, *call) } _ => vec![], } @@ -427,10 +427,8 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU fn compiler_statement_hyper_transition( &self, _dsym: DebugSymRef, - _ids: Vec, - _machine: V, - _exprs: Vec>, _state: V, + _call: Statement, ) -> Vec> { todo!("Compile expressions?") } diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 27ee0b39..ba6f965f 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -818,27 +818,23 @@ mod test { assert!(result.is_ok()); - // Wrong transition operator let circuit = " machine caller (signal n) (signal b: field) { - a', b, c' <== fibo(d, e, f + g) --> final; + -> final { + a', b, c' <== fibo(d, e, f + g); + } } "; let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); - assert!(result.is_err()); - let err = result.err().unwrap(); - assert_eq!( - err.to_string(), - "Unrecognized token `-` found at 99:100\nExpected one of \"->\"" - ); + assert!(result.is_ok()); - // No transition + // Wrong transition operator let circuit = " machine caller (signal n) (signal b: field) { - a', b, c' <== fibo(d, e, f + g); + a', b, c' <== fibo(d, e, f + g) --> final; } "; @@ -849,7 +845,7 @@ mod test { let err = result.err().unwrap(); assert_eq!( err.to_string(), - "Unrecognized token `;` found at 98:99\nExpected one of \"->\"" + "Unrecognized token `-` found at 99:100\nExpected one of \"->\" or \";\"" ); } } diff --git a/src/compiler/semantic/analyser.rs b/src/compiler/semantic/analyser.rs index 1314b89e..28011d1a 100644 --- a/src/compiler/semantic/analyser.rs +++ b/src/compiler/semantic/analyser.rs @@ -272,12 +272,16 @@ impl Analyser { Statement::SignalDecl(_, _) => {} Statement::WGVarDecl(_, _) => {} - Statement::HyperTransition(_, ids, _machine, exprs, _state) => { - // TODO analyze machine? analyze state? + Statement::HyperTransition(_, state, call) => { + self.analyse_statement(*call); + self.collect_id_usages(&[state]); + } + Statement::Call(_, ids, _machine, exprs) => { + // TODO analyze machine? + self.collect_id_usages(&ids); exprs .into_iter() - .for_each(|expr| self.analyse_expression(expr)); - self.collect_id_usages(&ids); + .for_each(|expr| self.analyse_expression(expr)) } } } diff --git a/src/compiler/setup_inter.rs b/src/compiler/setup_inter.rs index 8434bae9..2b2d4f18 100644 --- a/src/compiler/setup_inter.rs +++ b/src/compiler/setup_inter.rs @@ -250,7 +250,8 @@ impl SetupInterpreter { SignalAssignment(_, _, _) | WGAssignment(_, _, _) => vec![], SignalDecl(_, _) | WGVarDecl(_, _) => vec![], - HyperTransition(_, _, _, _, _) => todo!(), + Call(_, _, _, _) => todo!(), + HyperTransition(_, _, _) => todo!(), }; self.add_poly_constraints(result.into_iter().map(|cr| cr.anti_booly).collect()); diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 6c98822e..8dfd421d 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -206,7 +206,8 @@ impl<'a, F: Field + Hash> Interpreter<'a, F> { Block(_, stmts) => self.exec_step_block(stmts), Assert(_, _) => Ok(None), StateDecl(_, _, _) => Ok(None), - HyperTransition(_, _, _, _, _) => Ok(None), // TODO execute transition? + Call(_, _, _, _) => todo!("execute call?"), + HyperTransition(_, _, _) => todo!("execute hypertransition?"), } } diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index a297c090..82398485 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -35,15 +35,20 @@ pub enum Statement { Transition(DebugSymRef, V, Box>), // -> x { y } Block(DebugSymRef, Vec>), // { x } - /// Call into another machine with assertion and subsequent transition to another - /// state. + /// Call into another machine with assertion. /// Tuple values: /// - debug symbol reference; /// - assigned/asserted ids vector; /// - machine ID; - /// - call argument expressions vector; + /// - call argument expressions vector. + Call(DebugSymRef, Vec, V, Vec>), + /// Call into another machine with assertion and subsequent transition to another + /// state. + /// Tuple values: + /// - debug symbol reference; /// - next state ID. - HyperTransition(DebugSymRef, Vec, V, Vec>, V), + /// - machine call; + HyperTransition(DebugSymRef, V, Box>), } impl Debug for Statement { @@ -93,15 +98,11 @@ impl Debug for Statement { .join(" ") ) } - Statement::HyperTransition(_, ids, machine, exprs, state) => { - write!( - f, - "{:?} <== {} ({:?}) --> {:?};", - ids, - machine.name(), - exprs, - state - ) + Statement::Call(_, ids, machine, exprs) => { + write!(f, "{:?} <== {} ({:?});", ids, machine.name(), exprs) + } + Statement::HyperTransition(_, state, call) => { + write!(f, "{:?} -> {:?};", call, state) } } } @@ -121,7 +122,8 @@ impl Statement { Statement::StateDecl(dsym, _, _) => dsym.clone(), Statement::Transition(dsym, _, _) => dsym.clone(), Statement::Block(dsym, _) => dsym.clone(), - Statement::HyperTransition(dsym, _, _, _, _) => dsym.clone(), + Statement::Call(dsym, _, _, _) => dsym.clone(), + Statement::HyperTransition(dsym, _, _) => dsym.clone(), } } } diff --git a/src/parser/build.rs b/src/parser/build.rs index 03348fd8..3fea23b1 100644 --- a/src/parser/build.rs +++ b/src/parser/build.rs @@ -61,3 +61,11 @@ pub fn build_transition( ) -> Statement { Statement::Transition(dsym, id, Box::new(block)) } + +pub fn build_hyper_transition( + dsym: DebugSymRef, + state: Identifier, + call: Statement, +) -> Statement { + Statement::HyperTransition(dsym, state, Box::new(call)) +} diff --git a/src/parser/chiquito.lalrpop b/src/parser/chiquito.lalrpop index 35c2d04a..d1ee42f2 100644 --- a/src/parser/chiquito.lalrpop +++ b/src/parser/chiquito.lalrpop @@ -53,7 +53,8 @@ StatementType: Statement = { ParseWGVarDecl, ParseTransitionSimple, ParseTransition, - HyperTransition + HyperTransition, + Call, } AssertEq: Statement = { @@ -113,7 +114,11 @@ ParseTransition: Statement = { } HyperTransition: Statement = { - "<==" "(" ")" "->" => Statement::HyperTransition(dsym_factory.create(l,r), ids, machine, es, st), + "->" => build_hyper_transition(dsym_factory.create(l,r), st, call), +} + +Call: Statement = { + "<==" "(" ")" => Statement::Call(dsym_factory.create(l,r), ids, machine, es), } ParseSignalDecl: Statement = { From 49fb60946f3fdb909e64c7e322ea724641806a8a Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Mon, 26 Aug 2024 20:01:54 +0800 Subject: [PATCH 4/7] Add parser unit test for a no-arg call --- src/compiler/compiler.rs | 12 ++++++++++++ src/parser/build.rs | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index ba6f965f..09e708d5 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -831,6 +831,18 @@ mod test { assert!(result.is_ok()); + // TODO should no-arg calls be allowed? + let circuit = " + machine caller (signal n) (signal b: field) { + smth <== a() -> final; + } + "; + + let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); + let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); + + assert!(result.is_ok()); + // Wrong transition operator let circuit = " machine caller (signal n) (signal b: field) { diff --git a/src/parser/build.rs b/src/parser/build.rs index 3fea23b1..b5cee63a 100644 --- a/src/parser/build.rs +++ b/src/parser/build.rs @@ -67,5 +67,8 @@ pub fn build_hyper_transition( state: Identifier, call: Statement, ) -> Statement { - Statement::HyperTransition(dsym, state, Box::new(call)) + match call { + Statement::Call(_, _, _, _) => Statement::HyperTransition(dsym, state, Box::new(call)), + _ => unreachable!("Hyper transition must include a call statement"), + } } From cce3de0bb719de2321cc2ea785a81ba844d0e2fe Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Wed, 28 Aug 2024 13:05:30 +0800 Subject: [PATCH 5/7] Implement call as expression --- src/compiler/abepi.rs | 7 +-- src/compiler/compiler.rs | 17 -------- src/compiler/semantic/analyser.rs | 16 +++---- src/compiler/semantic/rules.rs | 3 ++ src/compiler/setup_inter.rs | 3 +- src/interpreter/expr.rs | 1 + src/interpreter/mod.rs | 3 +- src/parser/ast/expression.rs | 11 +++++ src/parser/ast/statement.rs | 71 +++++++++++++++++-------------- src/parser/build.rs | 7 +-- src/parser/chiquito.lalrpop | 8 ++-- 11 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/compiler/abepi.rs b/src/compiler/abepi.rs index b58685ae..dfefab56 100644 --- a/src/compiler/abepi.rs +++ b/src/compiler/abepi.rs @@ -65,8 +65,8 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU Statement::Transition(dsym, id, stmt) => { self.compiler_statement_transition(dsym, id, *stmt) } - Statement::HyperTransition(dsym, state, call) => { - self.compiler_statement_hyper_transition(dsym, state, *call) + Statement::HyperTransition(dsym, ids, call, state) => { + self.compiler_statement_hyper_transition(dsym, ids, call, state) } _ => vec![], } @@ -427,8 +427,9 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU fn compiler_statement_hyper_transition( &self, _dsym: DebugSymRef, + _ids: Vec, + _call: Expression, _state: V, - _call: Statement, ) -> Vec> { todo!("Compile expressions?") } diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 09e708d5..8e9d51be 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -842,22 +842,5 @@ mod test { let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); assert!(result.is_ok()); - - // Wrong transition operator - let circuit = " - machine caller (signal n) (signal b: field) { - a', b, c' <== fibo(d, e, f + g) --> final; - } - "; - - let debug_sym_ref_factory = DebugSymRefFactory::new("", circuit); - let result = TLDeclsParser::new().parse(&debug_sym_ref_factory, circuit); - - assert!(result.is_err()); - let err = result.err().unwrap(); - assert_eq!( - err.to_string(), - "Unrecognized token `-` found at 99:100\nExpected one of \"->\" or \";\"" - ); } } diff --git a/src/compiler/semantic/analyser.rs b/src/compiler/semantic/analyser.rs index 28011d1a..e5291ea4 100644 --- a/src/compiler/semantic/analyser.rs +++ b/src/compiler/semantic/analyser.rs @@ -272,16 +272,10 @@ impl Analyser { Statement::SignalDecl(_, _) => {} Statement::WGVarDecl(_, _) => {} - Statement::HyperTransition(_, state, call) => { - self.analyse_statement(*call); + Statement::HyperTransition(_, ids, call, state) => { + self.analyse_expression(call); self.collect_id_usages(&[state]); - } - Statement::Call(_, ids, _machine, exprs) => { - // TODO analyze machine? self.collect_id_usages(&ids); - exprs - .into_iter() - .for_each(|expr| self.analyse_expression(expr)) } } } @@ -319,6 +313,12 @@ impl Analyser { } => { self.extract_usages_expression(&sub); } + Expression::Call(_, fun, exprs) => { + self.collect_id_usages(&[fun]); + exprs + .into_iter() + .for_each(|expr| self.extract_usages_expression(&expr)); + } _ => {} } } diff --git a/src/compiler/semantic/rules.rs b/src/compiler/semantic/rules.rs index 5bf846e8..818162c1 100644 --- a/src/compiler/semantic/rules.rs +++ b/src/compiler/semantic/rules.rs @@ -43,6 +43,9 @@ fn undeclared_rule(analyser: &mut Analyser, expr: &Expression {} + Expression::Call(_, _, args) => { + args.iter().for_each(|arg| undeclared_rule(analyser, arg)); + } } } diff --git a/src/compiler/setup_inter.rs b/src/compiler/setup_inter.rs index 2b2d4f18..79598772 100644 --- a/src/compiler/setup_inter.rs +++ b/src/compiler/setup_inter.rs @@ -250,8 +250,7 @@ impl SetupInterpreter { SignalAssignment(_, _, _) | WGAssignment(_, _, _) => vec![], SignalDecl(_, _) | WGVarDecl(_, _) => vec![], - Call(_, _, _, _) => todo!(), - HyperTransition(_, _, _) => todo!(), + HyperTransition(_, _, _, _) => todo!(), }; self.add_poly_constraints(result.into_iter().map(|cr| cr.anti_booly).collect()); diff --git a/src/interpreter/expr.rs b/src/interpreter/expr.rs index afc85830..608ee813 100644 --- a/src/interpreter/expr.rs +++ b/src/interpreter/expr.rs @@ -82,6 +82,7 @@ pub(crate) fn eval_expr( Const(_, v) => Ok(Value::Field(F::from_big_int(v))), True(_) => Ok(Value::Bool(true)), False(_) => Ok(Value::Bool(false)), + Call(_, _, _) => todo!(), } .map_err(|msg| Message::RuntimeErr { msg, diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8dfd421d..a2b7938d 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -206,8 +206,7 @@ impl<'a, F: Field + Hash> Interpreter<'a, F> { Block(_, stmts) => self.exec_step_block(stmts), Assert(_, _) => Ok(None), StateDecl(_, _, _) => Ok(None), - Call(_, _, _, _) => todo!("execute call?"), - HyperTransition(_, _, _) => todo!("execute hypertransition?"), + HyperTransition(_, _, _, _) => todo!("execute hypertransition?"), } } diff --git a/src/parser/ast/expression.rs b/src/parser/ast/expression.rs index 61556d11..d18c2aff 100644 --- a/src/parser/ast/expression.rs +++ b/src/parser/ast/expression.rs @@ -193,6 +193,12 @@ pub enum Expression { Const(DebugSymRef, F), True(DebugSymRef), False(DebugSymRef), + /// Function or machine call. + /// Tuple values: + /// - debug symbol reference; + /// - function/machine ID; + /// - call argument expressions vector. + Call(DebugSymRef, V, Vec>), } // Shorthand for BigInt expression @@ -217,6 +223,7 @@ impl Expression { Const(_, _) => true, True(_) => false, False(_) => false, + Call(_, _, _) => todo!(), } } @@ -234,6 +241,7 @@ impl Expression { when_true.is_logic() } + Expression::Call { .. } => todo!(), _ => false, } } @@ -247,6 +255,7 @@ impl Expression { Expression::Const(dsym, _) => dsym, Expression::True(dsym) => dsym, Expression::False(dsym) => dsym, + Expression::Call(dsym, _, _) => dsym, } } @@ -260,6 +269,7 @@ impl Expression { Expression::Query(_, _) => false, Expression::True(_) => false, Expression::False(_) => false, + Expression::Call(_, _, _) => false, } } } @@ -315,6 +325,7 @@ impl Debug for Expression { Expression::True(_) => write!(f, "true"), Expression::False(_) => write!(f, "false"), + Expression::Call(_, fun, exprs) => write!(f, "{:?}({:?})", fun, exprs), } } } diff --git a/src/parser/ast/statement.rs b/src/parser/ast/statement.rs index 82398485..896cd50e 100644 --- a/src/parser/ast/statement.rs +++ b/src/parser/ast/statement.rs @@ -13,42 +13,42 @@ pub struct TypedIdDecl { #[derive(Clone)] pub enum Statement { - Assert(DebugSymRef, Expression), // assert x; - - SignalAssignment(DebugSymRef, Vec, Vec>), // x <-- y; - SignalAssignmentAssert(DebugSymRef, Vec, Vec>), // x <== y; - WGAssignment(DebugSymRef, Vec, Vec>), // x = y; - - IfThen(DebugSymRef, Box>, Box>), // if x { y } + /// assert x; + Assert(DebugSymRef, Expression), + /// x <-- y; + SignalAssignment(DebugSymRef, Vec, Vec>), + /// x <== y; + SignalAssignmentAssert(DebugSymRef, Vec, Vec>), + /// x = y; + WGAssignment(DebugSymRef, Vec, Vec>), + /// if x { y } + IfThen(DebugSymRef, Box>, Box>), + /// if x { y } else { z } IfThenElse( DebugSymRef, Box>, Box>, Box>, - ), // if x { y } else { z } - - SignalDecl(DebugSymRef, Vec>), // signal x; - WGVarDecl(DebugSymRef, Vec>), // var x; - - StateDecl(DebugSymRef, V, Box>), // state x { y } + ), + /// signal x; + SignalDecl(DebugSymRef, Vec>), + /// var x; + WGVarDecl(DebugSymRef, Vec>), + /// state x { y } + StateDecl(DebugSymRef, V, Box>), /// Transition to another state. - Transition(DebugSymRef, V, Box>), // -> x { y } - - Block(DebugSymRef, Vec>), // { x } - /// Call into another machine with assertion. - /// Tuple values: - /// - debug symbol reference; - /// - assigned/asserted ids vector; - /// - machine ID; - /// - call argument expressions vector. - Call(DebugSymRef, Vec, V, Vec>), + /// -> x { y } + Transition(DebugSymRef, V, Box>), + /// { x } + Block(DebugSymRef, Vec>), /// Call into another machine with assertion and subsequent transition to another /// state. /// Tuple values: /// - debug symbol reference; - /// - next state ID. - /// - machine call; - HyperTransition(DebugSymRef, V, Box>), + /// - assigned signal IDs; + /// - call expression; + /// - next state ID; + HyperTransition(DebugSymRef, Vec, Expression, V), } impl Debug for Statement { @@ -98,11 +98,17 @@ impl Debug for Statement { .join(" ") ) } - Statement::Call(_, ids, machine, exprs) => { - write!(f, "{:?} <== {} ({:?});", ids, machine.name(), exprs) - } - Statement::HyperTransition(_, state, call) => { - write!(f, "{:?} -> {:?};", call, state) + Statement::HyperTransition(_, ids, call, state) => { + write!( + f, + "{:?} <== {:?} -> {:?};", + ids.iter() + .map(|id| id.name()) + .collect::>() + .join(", "), + call, + state + ) } } } @@ -122,8 +128,7 @@ impl Statement { Statement::StateDecl(dsym, _, _) => dsym.clone(), Statement::Transition(dsym, _, _) => dsym.clone(), Statement::Block(dsym, _) => dsym.clone(), - Statement::Call(dsym, _, _, _) => dsym.clone(), - Statement::HyperTransition(dsym, _, _) => dsym.clone(), + Statement::HyperTransition(dsym, _, _, _) => dsym.clone(), } } } diff --git a/src/parser/build.rs b/src/parser/build.rs index b5cee63a..e179f875 100644 --- a/src/parser/build.rs +++ b/src/parser/build.rs @@ -62,13 +62,14 @@ pub fn build_transition( Statement::Transition(dsym, id, Box::new(block)) } -pub fn build_hyper_transition( +pub fn build_hyper_transition( dsym: DebugSymRef, + ids: Vec, + call: Expression, state: Identifier, - call: Statement, ) -> Statement { match call { - Statement::Call(_, _, _, _) => Statement::HyperTransition(dsym, state, Box::new(call)), + Expression::Call(_, _, _) => Statement::HyperTransition(dsym, ids, call, state), _ => unreachable!("Hyper transition must include a call statement"), } } diff --git a/src/parser/chiquito.lalrpop b/src/parser/chiquito.lalrpop index d1ee42f2..e05882f2 100644 --- a/src/parser/chiquito.lalrpop +++ b/src/parser/chiquito.lalrpop @@ -54,7 +54,6 @@ StatementType: Statement = { ParseTransitionSimple, ParseTransition, HyperTransition, - Call, } AssertEq: Statement = { @@ -114,11 +113,11 @@ ParseTransition: Statement = { } HyperTransition: Statement = { - "->" => build_hyper_transition(dsym_factory.create(l,r), st, call), + "<==" "->" => build_hyper_transition(dsym_factory.create(l,r), ids, call, st), } -Call: Statement = { - "<==" "(" ")" => Statement::Call(dsym_factory.create(l,r), ids, machine, es), +Call: Expression = { + "(" ")" => Expression::Call(dsym_factory.create(l,r), fun, es), } ParseSignalDecl: Statement = { @@ -212,6 +211,7 @@ ExpressionTerm: Expr = { "true" => Expression::True(dsym_factory.create(l,r)), "false" => Expression::False(dsym_factory.create(l,r)), "(" ")" => e, + Call } ParseBinOp: Expr = { From 9712c582edd519dbbcda382b0f33b35cae94d307 Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Wed, 28 Aug 2024 13:11:14 +0800 Subject: [PATCH 6/7] Move call grammar declaration --- src/parser/chiquito.lalrpop | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/parser/chiquito.lalrpop b/src/parser/chiquito.lalrpop index e05882f2..36b50a3c 100644 --- a/src/parser/chiquito.lalrpop +++ b/src/parser/chiquito.lalrpop @@ -116,10 +116,6 @@ HyperTransition: Statement = { "<==" "->" => build_hyper_transition(dsym_factory.create(l,r), ids, call, st), } -Call: Expression = { - "(" ")" => Expression::Call(dsym_factory.create(l,r), fun, es), -} - ParseSignalDecl: Statement = { "signal" => Statement::SignalDecl(dsym_factory.create(l,r), ids), } @@ -205,6 +201,10 @@ ParsePrefix: Expr = { ExpressionTerm } +Call: Expr = { + "(" ")" => Expression::Call(dsym_factory.create(l,r), fun, es), +} + ExpressionTerm: Expr = { => build_query(id, dsym_factory.create(l,r)), => lit, From ad67776bf8888bbc5ef1b9a188881c036e818215 Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Wed, 28 Aug 2024 16:38:26 +0800 Subject: [PATCH 7/7] Add TODOs --- src/compiler/abepi.rs | 2 +- src/compiler/compiler.rs | 2 +- src/compiler/setup_inter.rs | 2 +- src/interpreter/expr.rs | 4 +++- src/interpreter/mod.rs | 2 +- src/parser/ast/expression.rs | 8 ++++++-- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compiler/abepi.rs b/src/compiler/abepi.rs index dfefab56..03b488ff 100644 --- a/src/compiler/abepi.rs +++ b/src/compiler/abepi.rs @@ -431,7 +431,7 @@ impl + TryInto + Clone + Debug, V: Clone + Debug> CompilationU _call: Expression, _state: V, ) -> Vec> { - todo!("Compile expressions?") + todo!("Compile expressions? Needs specs") } } diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index 8e9d51be..e717a993 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -831,7 +831,7 @@ mod test { assert!(result.is_ok()); - // TODO should no-arg calls be allowed? + // TODO should no-arg calls be allowed? Needs more specs for function/machine calls let circuit = " machine caller (signal n) (signal b: field) { smth <== a() -> final; diff --git a/src/compiler/setup_inter.rs b/src/compiler/setup_inter.rs index 79598772..30130eaa 100644 --- a/src/compiler/setup_inter.rs +++ b/src/compiler/setup_inter.rs @@ -250,7 +250,7 @@ impl SetupInterpreter { SignalAssignment(_, _, _) | WGAssignment(_, _, _) => vec![], SignalDecl(_, _) | WGVarDecl(_, _) => vec![], - HyperTransition(_, _, _, _) => todo!(), + HyperTransition(_, _, _, _) => todo!("Implement compilation for hyper transitions"), }; self.add_poly_constraints(result.into_iter().map(|cr| cr.anti_booly).collect()); diff --git a/src/interpreter/expr.rs b/src/interpreter/expr.rs index 608ee813..d0eb3f9b 100644 --- a/src/interpreter/expr.rs +++ b/src/interpreter/expr.rs @@ -82,7 +82,9 @@ pub(crate) fn eval_expr( Const(_, v) => Ok(Value::Field(F::from_big_int(v))), True(_) => Ok(Value::Bool(true)), False(_) => Ok(Value::Bool(false)), - Call(_, _, _) => todo!(), + Call(_, _, _) => { + todo!("Needs specs. Evaluate the argument expressions, evaluate the function output?") + } } .map_err(|msg| Message::RuntimeErr { msg, diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index a2b7938d..fc71787c 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -206,7 +206,7 @@ impl<'a, F: Field + Hash> Interpreter<'a, F> { Block(_, stmts) => self.exec_step_block(stmts), Assert(_, _) => Ok(None), StateDecl(_, _, _) => Ok(None), - HyperTransition(_, _, _, _) => todo!("execute hypertransition?"), + HyperTransition(_, _, _, _) => todo!("Needs specs"), } } diff --git a/src/parser/ast/expression.rs b/src/parser/ast/expression.rs index d18c2aff..941641ad 100644 --- a/src/parser/ast/expression.rs +++ b/src/parser/ast/expression.rs @@ -223,7 +223,9 @@ impl Expression { Const(_, _) => true, True(_) => false, False(_) => false, - Call(_, _, _) => todo!(), + Call(_, _, _) => { + todo!("Needs specs. For a function call, depends on the function return type?") + } } } @@ -241,7 +243,9 @@ impl Expression { when_true.is_logic() } - Expression::Call { .. } => todo!(), + Expression::Call { .. } => { + todo!("Needs specs. For a function call, depends on the function return type?") + } _ => false, } }