pub struct Parser {
tokens: Vec<Token>,
error: ErrorEmitter,
}Fields§
§tokens: Vec<Token>§error: ErrorEmitterImplementations§
Source§impl Parser
impl Parser
pub fn new(filename: &str, source: Chars<'_>, tokens: Vec<Token>) -> Self
pub fn parse( &self, ) -> Result<(String, u32, Vec<Constant>, Vec<Witness>, Vec<Statement>)>
Sourcefn parse_header<'a>(
&self,
iter: &mut impl Iterator<Item = &'a Token>,
) -> Result<u32>
fn parse_header<'a>( &self, iter: &mut impl Iterator<Item = &'a Token>, ) -> Result<u32>
Parse the file header: k=N; field=“…”;
The first thing that has to be declared in the source code is the constant “k” which defines 2^k rows that the circuit needs to successfully execute.
Then we declare the field we’re working in.
Sourcefn parse_sections<'a>(
&self,
iter: &mut impl Iterator<Item = &'a Token>,
) -> Result<(String, SectionTokens)>
fn parse_sections<'a>( &self, iter: &mut impl Iterator<Item = &'a Token>, ) -> Result<(String, SectionTokens)>
Parse all sections (constant, witness, circuit) and return their tokens.
Sections “constant”, “witness”, and “circuit” are the sections we must be declaring in our source code. When we find one, we’ll take all the tokens found in the section and place them in their respective vec.
NOTE: Currently this logic depends on the fact that the sections are closed off with braces. This should be revisited later when we decide to add other lang functionality that also depends on using braces.
Sourcefn absorb_section_tokens<'a>(
&self,
iter: &mut impl Iterator<Item = &'a Token>,
dest: &mut Vec<Token>,
) -> Result<()>
fn absorb_section_tokens<'a>( &self, iter: &mut impl Iterator<Item = &'a Token>, dest: &mut Vec<Token>, ) -> Result<()>
Absorb tokens from iterator until a closing brace is found. Validates that no keywords are used in improper places.
Sourcefn validate_section_namespace(
&self,
section_name: &str,
tokens: &[Token],
existing_ns: Option<String>,
) -> Result<String>
fn validate_section_namespace( &self, section_name: &str, tokens: &[Token], existing_ns: Option<String>, ) -> Result<String>
Validate namespace consistency across sections. All sections must use the same namespace, and it must not be a reserved name.
Sourcefn build_constants(&self, tokens: &[Token]) -> Result<Vec<Constant>>
fn build_constants(&self, tokens: &[Token]) -> Result<Vec<Constant>>
Build constants from section tokens. Validates constant types against the CONSTANT_TYPES table.
Sourcefn build_witnesses(&self, tokens: &[Token]) -> Result<Vec<Witness>>
fn build_witnesses(&self, tokens: &[Token]) -> Result<Vec<Witness>>
Build witnesses from section tokens.
Sourcefn parse_typed_section(
&self,
section_name: &str,
tokens: &[Token],
) -> Result<IndexMap<String, (Token, Token)>>
fn parse_typed_section( &self, section_name: &str, tokens: &[Token], ) -> Result<IndexMap<String, (Token, Token)>>
Parse a typed section (constant or witness) into an IndexMap.
Both sections have the same structure: pairs of ‘
Sourcefn validate_section_entry(
&self,
section_type: &str,
name: &str,
name_token: &Token,
type_token: &Token,
) -> Result<()>
fn validate_section_entry( &self, section_type: &str, name: &str, name_token: &Token, type_token: &Token, ) -> Result<()>
Common validation for constant/witness entries. Ensures name and type tokens are symbols and match expected values.
Sourcefn check_section_structure(&self, section: &str, tokens: &[Token]) -> Result<()>
fn check_section_structure(&self, section: &str, tokens: &[Token]) -> Result<()>
Routine checks on section structure. Validates that sections have proper opening/closing braces and correct element counts.
Sourcefn parse_ast_circuit(&self, tokens: &[Token]) -> Result<Vec<Statement>>
fn parse_ast_circuit(&self, tokens: &[Token]) -> Result<Vec<Statement>>
Parse the circuit section into statements.
The statement layouts/syntax in the language are as follows:
C = poseidon_hash(pub_x, pub_y, value, token, serial);
| | | | |
V V V V V
variable opcode arg arg
assign
constrain_instance(C);
| |
V V
opcode arg
inner opcode arg
|
constrain_instance(ec_get_x(foo));
| |
V V
opcode arg as opcodeIn the latter, we want to support nested function calls, e.g.:
constrain_instance(ec_get_x(token_commit));The inner call’s result would still get pushed on the heap, but it will not be accessible in any other scope.
In certain opcodes, we also support literal types, and the opcodes can return a variable type after running the operation. e.g.
one = witness_base(1);
zero = witness_base(0);The literal type is used only in the function call’s scope, but the result is then accessible on the heap to be used by further computation.
Regarding multiple return values from opcodes, this is perhaps not necessary for the current language scope, as this is a low level representation. Note that it could be relatively easy to modify the parsing logic to support that here. For now we’ll defer it, and if at some point we decide that the language is too expressive and noisy, we’ll consider having multiple return types. It also very much depends on the type of functions/opcodes that we want to support.
Sourcefn validate_statement_brackets(&self, statement: &[Token]) -> Result<()>
fn validate_statement_brackets(&self, statement: &[Token]) -> Result<()>
Validate matching brackets in a statement. Ensures parentheses and brackets are balanced and properly nested.
Sourcefn parse_statement(
&self,
iter: &mut Peekable<Iter<'_, Token>>,
) -> Result<Statement>
fn parse_statement( &self, iter: &mut Peekable<Iter<'_, Token>>, ) -> Result<Statement>
Parse a single statement from tokens. Determines if this is an assignment (var = …) or a direct call (opcode(…)).
Sourcefn parse_opcode_call(
&self,
token: &Token,
iter: &mut Peekable<Iter<'_, Token>>,
stmt: &mut Statement,
) -> Result<()>
fn parse_opcode_call( &self, token: &Token, iter: &mut Peekable<Iter<'_, Token>>, stmt: &mut Statement, ) -> Result<()>
Parse an opcode call and fill in the statement. The assumption here is that the current token is a function call, so we check if it’s legit and start digging.
Sourcefn parse_function_call(
&self,
token: &Token,
iter: &mut Peekable<Iter<'_, Token>>,
) -> Result<Vec<Arg>>
fn parse_function_call( &self, token: &Token, iter: &mut Peekable<Iter<'_, Token>>, ) -> Result<Vec<Arg>>
Parse a function call and its arguments. Handles nested function calls recursively, creating intermediate variables for inner call results.
Sourcefn expect_token_type(&self, token: &Token, expected: TokenType) -> Result<()>
fn expect_token_type(&self, token: &Token, expected: TokenType) -> Result<()>
Check that a token has the expected type.
Sourcefn next_tuple3<I, T>(iter: &mut I) -> Option<(T, T, T)>where
I: Iterator<Item = T>,
fn next_tuple3<I, T>(iter: &mut I) -> Option<(T, T, T)>where
I: Iterator<Item = T>,
Get next 3 items from an iterator as a tuple.
Sourcefn next_tuple4<I, T>(iter: &mut I) -> Option<(T, T, T, T)>where
I: Iterator<Item = T>,
fn next_tuple4<I, T>(iter: &mut I) -> Option<(T, T, T, T)>where
I: Iterator<Item = T>,
Get next 4 items from an iterator as a tuple.
Auto Trait Implementations§
impl Freeze for Parser
impl RefUnwindSafe for Parser
impl Send for Parser
impl Sync for Parser
impl Unpin for Parser
impl UnwindSafe for Parser
Blanket Implementations§
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2where
T: SharedNiching<N1, N2>,
N1: Niching<T>,
N2: Niching<T>,
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2where
T: SharedNiching<N1, N2>,
N1: Niching<T>,
N2: Niching<T>,
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Pointee for T
impl<T> Pointee for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.