From 3ed7e13b3dfc36f0c4961beb1323a321bb193001 Mon Sep 17 00:00:00 2001 From: dev-sptg Date: Tue, 9 Feb 2021 18:55:36 +0200 Subject: [PATCH 001/108] Fix build for windows 64 bit --- .github/workflows/release.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 22bbaea1a8..f65b75fc4f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,7 +95,6 @@ jobs: windows: name: Windows runs-on: windows-latest - continue-on-error: true steps: - name: Checkout uses: actions/checkout@v1 @@ -111,8 +110,11 @@ jobs: - name: Install LLVM and Clang uses: KyleMayes/install-llvm-action@v1 with: - version: "10.0" - directory: ~ / .clang + version: "11" + directory: ${{ runner.temp }}/llvm + + - name: Set LIBCLANG_PATH + run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV - name: Build Leo run: | @@ -125,18 +127,13 @@ jobs: - name: Zip run: | - mkdir tempdir - mv target/release/leo tempdir - cd tempdir - Compress-Archive leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu leo - cd .. - mv leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu . + Compress-Archive target/release/leo.exe leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-msvc.zip - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: files: | - leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-gnu.zip + leo-${{ steps.get_version.outputs.version }}-x86_64-pc-windows-msvc.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From dde8ab59faeee06a97e77f89a549c1378f1127ef Mon Sep 17 00:00:00 2001 From: gluax Date: Mon, 22 Mar 2021 14:38:38 -0400 Subject: [PATCH 002/108] initial commit, so I can open retroactive pr --- grammar/abnf-grammar.txt | 1089 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1089 insertions(+) create mode 100644 grammar/abnf-grammar.txt diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt new file mode 100644 index 0000000000..ff93d19c09 --- /dev/null +++ b/grammar/abnf-grammar.txt @@ -0,0 +1,1089 @@ +; Leo Library +; +; Copyright (C) 2021 Aleo Systems Inc. +; +; Author: Alessandro Coglio (acoglio on GitHub) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Format Note +; ----------- + +; The ABNF standard requires grammars to consist of lines terminated by CR LF +; (i.e. carriage return followed by line feed, DOS/Windows-style), +; as explained in the background on ABNF later in this file. +; This file's lines are therefore terminated by CR LF. +; To avoid losing this requirement across systems, +; this file is marked as 'text eol=crlf' in .gitattributes: +; this means that the file is textual, enabling visual diffs, +; but its lines will always be terminated by CR LF on any system. + +; Note that this CR LF requirement only applies to the grammar files themselves. +; It does not apply to the lines of the languages described by the grammar. +; ABNF grammar may describe any kinds of languages, +; with any kind of line terminators, +; or even without line terminators at all (e.g. for "binary" languages). + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Introduction +; ------------ + +; This file contains an initial draft of +; a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. +; Background on ABNF is provided later in this file. + +; The initial motivation for creating an ABNF grammar of Leo was that +; we have a formally verified parser of ABNF grammars +; (at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; +; also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) +; which we have used to parse this ABNF grammar of Leo +; into a formal representation, in the ACL2 theorem prover, +; of the Leo concrete syntax. +; The parsing of this grammar file into an ACL2 representation +; happens every time the ACL2 formalization of Leo is built. + +; In addition to that initial motivation, +; this ABNF grammar has now the additional and primary purpose of +; providing an official definition of the syntax of Leo +; that is both human-readable and machine-readable. +; This grammar will be part of the (upcoming) Leo language reference, +; of the Leo Language Formal Specification +; (i.e. the LaTeX document in the leo-semantics repo), +; and of the ACL2 formalization of Leo (which was the initial motivation). +; It has also been suggested that it may be used to generate tests. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Background on ABNF +; ------------------ + +; ABNF is an Internet standard: +; see https://www.rfc-editor.org/info/rfc5234 +; and https://www.rfc-editor.org/info/rfc7405. +; It is used to specify the syntax of JSON, HTTP, and other standards. + +; The following is copied (and "un-LaTeX'd") from the aforementioned paper +; (at https://www.kestrel.edu/people/coglio/vstte18.pdf). + +; ABNF adds conveniences and makes slight modifications +; to Backus-Naur Form (BNF), +; without going beyond context-free grammars. + +; Instead of BNF's angle-bracket notation for nonterminals, +; ABNF uses case-insensitive names consisting of letters, digits, and dashes, +; e.g. HTTP-message and IPv6address. +; ABNF includes an angle-bracket notation for prose descriptions, +; e.g. , +; usable as last resort in the definiens of a nonterminal. + +; While BNF allows arbitrary terminals, +; ABNF uses only natural numbers as terminals, +; and denotes them via: +; (i) binary, decimal, or hexadecimal sequences, +; e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A +; all denote the string '1 3 10'; +; (ii) binary, decimal, or hexadecimal ranges, +; e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 +; (an ASCII digit); +; (iii) case-sensitive ASCII strings, +; e.g. %s"Ab" denotes the string '65 98'; +; and (iv) case-insensitive ASCII strings, +; e.g. %i"ab", or just "ab", denotes +; any string among +; '65 66', +; '65 98', +; '97 66', and +; '97 98'. +; ABNF terminals in suitable sets represent ASCII or Unicode characters. + +; ABNF allows repetition prefixes n*m, +; where n and m are natural numbers in decimal notation; +; if absent, +; n defaults to 0, and +; m defaults to infinity. +; For example, +; 1*4HEXDIG denotes one to four HEXDIGs, +; *3DIGIT denotes up to three DIGITs, and +; 1*OCTET denotes one or more OCTETs. +; A single n prefix +; abbreviates n*n, +; e.g. 3DIGIT denotes three DIGITs. + +; Instead of BNF's |, ABNF uses / to separate alternatives. +; Repetition prefixes have precedence over juxtapositions, +; which have precedence over /. +; Round brackets group things and override the aforementioned precedence rules, +; e.g. *(WSP / CRLF WSP) denotes strings +; obtained by repeating, zero or more times, +; either (i) a WSP or (ii) a CRLF followed by a WSP. +; Square brackets also group things but make them optional, +; e.g. [":" port] is equivalent to 0*1(":" port). + +; Instead of BNF's ::=, ABNF uses = to define nonterminals, +; and =/ to incrementally add alternatives +; to previously defined nonterminals. +; For example, the rule BIT = "0" / "1" +; is equivalent to BIT = "0" followed by BIT =/ "1". + +; The syntax of ABNF itself is formally specified in ABNF +; (in Section 4 of the aforementioned RFC 5234, +; after the syntax and semantics of ABNF +; are informally specified in natural language +; (in Sections 1, 2, and 3 of the aforementioned RFC 5234). +; The syntax rules of ABNF prescribe the ASCII codes allowed for +; white space (spaces and horizontal tabs), +; line endings (carriage returns followed by line feeds), +; and comments (semicolons to line endings). + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Structure +; --------- + +; Language specifications often define the syntax of their languages via +; (i) a lexical grammar that describes how +; sequence of characters are parsed into tokens, and +; (ii) a syntactic grammar that described how +; tokens are parsed into expressions, statements, etc. +; (The adjectives 'lexical' and 'syntactic' are +; the ones used in the Java language specification; +; other terms may be used by other languages, +; but the essence is similar.) +; The situation is sometimes more complex, +; with multiple passes (e.g. Unicode escape processing in Java), +; but the division between lexical and syntactic (in the sense above) stands. + +; In the aforementioned language specifications, +; both the lexical and syntactic grammars +; are normally written in a context-free grammar notation, +; augmented with natural language that may assert, for instance, +; that tokenization always takes the longest sequence that constitutes a token. + +; This dual structure appears to be motivated by the fact that +; concerns of white space, line endings, etc. +; can be handled by the lexical grammar, +; allowing the syntactic grammar to focus on the more important structure. +; Handling both aspects in a single context-free grammar may be unwieldy, +; so having two grammars provides more clarity and readability. + +; In contrast, PEG (Parsing Expression Grammar) formalisms like Pest +; naturally embody a procedural interpretation +; that can handle white space and tokenization in just one manageable grammar. +; However, this procedural interpretaion may be sometimes +; less clear and readable to humans than context-free rules. +; Indeed, context-free grammar are commonly used to documentat languages. + +; ABNF is a context-free grammar notation, +; with no procedural interpretation, +; and therefore it makes sense to define +; separate lexical and syntactic ABNF grammars for Leo. +; Conceptually, the two grammars define two subsequent processing phases, +; as detailed below. +; However, a parser implementation does not need to perform +; two strictly separate phases (in fact, it typically does not), +; so long as it produces the same final result. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Operator Precedence +; ------------------- + +; We formulate the grammar rules for expressions +; in a way that describes the relative precedence of operators, +; as often done in language syntax specifications. + +; For instance, consider the rules +; +; multiplicative-expression = +; exponential-expression +; / multiplicative-expression "*" exponential-expression +; / multiplicative-expression "/" exponential-expression +; +; additive-expression = +; multiplicative-expression +; / additive-expression "+" multiplicative-expression +; / additive-expression "-" multiplicative-expression +; +; this rule tells us that the additive operators '+' and '-' have +; lower precedence than the multiplicative operators '*' and '/', +; and that both the additive and multiplicative operators associate to the left. +; This may be best understood via the examples given below. + +; According to the rules, the expression +; +; x + y * z +; +; can only be parsed as +; +; + +; / \ +; x * +; / \ +; y z +; +; and not as +; +; * +; / \ +; + z +; / \ +; x y +; +; because a multiplicative expression cannot have an additive expression +; as first sub-expression, as it would in the second tree above. + +; Also according to the rules, the expression +; +; x + y + z +; +; can only be parsed as +; +; + +; / \ +; + z +; / \ +; x y +; +; and not as +; +; + +; / \ +; x + +; / \ +; y z +; +; because an additive expression cannot have an additive expression +; as second sub-expression, as it would in the second tree above. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Naming Convention +; ----------------- + +; For this ABNF grammar, we choose nonterminal names +; that consist of complete English words, separated by dashes, +; and that describe the construct the way it is in English. +; For instance, we use the name 'conditional-statement' +; to describe conditional statements. + +; At the same time, we attempt to establish +; a precise and "official" nomenclature for the Leo constructs, +; by way of the nonterminal names that define their syntax. +; For instance, the rule +; +; group-literal = product-group-literal +; / affine-group-literal +; +; tells us that there are two kinds of group literals, +; namely product group literals and affine group literals. +; This is more precise than describing them as +; integers (which are not really group elements per se), +; or points (they are all points, just differently specified), +; or being singletons vs. pairs (which is a bit generic). + +; The only exception to the nomenclature-establishing role of the grammar +; is the fact that, as discussed above, +; we write the grammar rules in a way that determines +; the relative precedence and the associativity of expression operators, +; and that therefore we have rules like +; +; unary-expression = primary-expression +; / "!" unary-expression +; / "-" unary-expression +; +; In order to allow the recursion of the rule to stop, +; we need to regard, in the grammar, a primary expression as a unary expression. +; However, this is just a grammatical artifact: +; ontologically, a primary expression is not really a unary expression, +; because a unary expression is one that consists of +; a unary operator and an operand sub-expression. +; These terminological "exceptions" should be easy to identify in the rules. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Lexical Grammar +; --------------- + +; A Leo file is a finite sequence of Unicode characters, +; represented as Unicode code points, +; which are numbers in the range form 0 to 10FFFFh. +; These are captured by the ABNF rule 'character' below. + +; The lexical grammar defines how, conceptually, +; the sequence of characters is turned into +; a sequence of tokens, comments, and whitespaces. + +; As stated, the lexical grammar is ambiguous. +; For example, the sequence of characters '**' (i.e. two stars) +; could be equally parsed as two '*' symbol tokens or one '**' symbol token +; (see rule for 'symbol' below). +; As another example, the sequence or characters '' +; (i.e. carriage return followed by line feed) +; could be equally parsed as two line terminators or one +; (see rule for 'newline'). + +; Thus, as often done in language syntax definitions, +; the lexical grammar is disambiguated by +; the extra-grammatical requirement that +; the longest possible sequence of characters is always parsed. +; This way, '**' must be parsed as one '**' symbol token, +; and '' must be parsed as one line terminator. +; (We should formalize this requirement, +; along with the other extra-grammatical requirements given below, +; and formally prove that they indeed make +; the lexical grammar of Leo unambiguous.) + +; As mentioned above, a character is any Unicode code point. +; This grammar does not say how those are encoded in files (e.g. UTF-8): +; it starts with a decoded sequence of Unicode code points. +; Note that we allow any value, +; even though some values may not be used according to the Unicode standard. + +character = %x0-10FFFF ; any Unicode code point + +; We give names to certain ASCII characters. + +horizontal-tab = %x9 + +line-feed = %xA + +carriage-return = %xD + +space = %x20 + +double-quote = %x22 + +; We give names to complements of certain ASCII characters. +; These consist of all the Unicode characters except for one or two. + +not-double-quote = %x0-22 / %x24-10FFFF ; anything but " + +not-star = %x0-29 / %x2B-10FFFF ; anything but * + +not-line-feed-or-carriage-return = %x0-9 / %xB-C / %xE-10FFFF + ; anything but LF or CR + +not-star-or-slash = %x0-29 / %x2B-2E / %x30-10FFFF ; anything but * or / + +; Lines in Leo may be terminated via +; a single carriage return, +; a line feed, +; or a carriage return immediately followed by a line feed. +; Note that the latter combination constitutes a single line terminator, +; according to the extra-grammatical rule of the longest sequence. + +newline = line-feed / carriage-return / carriage-return line-feed + +; Line terminators form whitespace, along with spaces and horizontal tabs. + +whitespace = space / horizontal-tab / newline + +; There are two kinds of comments in Leo, as in other languages. +; One is block comments of the form '/* ... */', +; and the other is end-of-line comments '// ...'. +; The first kind start at '/*' and end at the first '*/', +; possibly spanning multiple (partial) lines; +; they do no nest. +; The second kind start at '//' and extend till the end of the line. +; The rules about comments given below are similar to +; the ones used in the Java language specification. + +comment = block-comment / end-of-line-comment + +block-comment = "/*" rest-of-block-comment + +rest-of-block-comment = "*" rest-of-block-comment-after-star + / not-star rest-of-block-comment + +rest-of-block-comment-after-star = "/" + / "*" rest-of-block-comment-after-star + / not-star-or-slash rest-of-block-comment + +end-of-line-comment = "//" *not-line-feed-or-carriage-return newline + +; Below are the keywords in the Leo language. +; They cannot be used as identifiers. + +keyword = %s"address" + / %s"as" + / %s"bool" + / %s"circuit" + / %s"console" + / %s"const" + / %s"else" + / %s"false" + / %s"field" + / %s"for" + / %s"function" + / %s"group" + / %s"i8" + / %s"i16" + / %s"i32" + / %s"i64" + / %s"i128" + / %s"if" + / %s"import" + / %s"in" + / %s"input" + / %s"let" + / %s"mut" + / %s"return" + / %s"Self" + / %s"self" + / %s"static" + / %s"string" + / %s"true" + / %s"u8" + / %s"u16" + / %s"u32" + / %s"u64" + / %s"u128" + +; The following rules define (ASCII) digits +; and (uppercase and lowercase) letters. + +digit = %x30-39 ; 0-9 + +uppercase-letter = %x41-5A ; A-Z + +lowercase-letter = %x61-7A ; a-z + +letter = uppercase-letter / lowercase-letter + +; An identifier is a non-empty sequence of letters, digits, and underscores, +; starting with a letter. +; It must not be a keyword: this is an extra-grammatical constraint. + +identifier = letter *( letter / digit / "_" ) ; but not a keyword + +; A package name consists of one or more segments separated by single dashes, +; where each segment is a non-empty sequence of lowercase letters and digits. + +package-name = 1*( lowercase-letter / digit ) + *( "-" 1*( lowercase-letter / digit ) ) + +; An address starts with 'aleo1' +; and continues with exactly 58 lowercase letters and digits. +; Thus an address always consists of 63 characters. + +address = %s"aleo1" 58( lowercase-letter / digit ) + +; A format string is a sequence of characters, other than double quote, +; surrounded by double quotes. +; Within a format string, substrings '{}' are distinguished as containers +; (these are the ones that may be matched with values +; whose textual representation replaces the containers +; in the printed string). +; There is an implicit extra-grammatical requirements that +; the explicit 'format-container' instances include +; all the occurrences of '{}' in the parsed character sequence: +; that is, there may not be two contiguous 'not-double-quote' instances +; that are '{' and '}'. + +format-string-container = "{}" + +format-string = double-quote + *( not-double-quote / format-string-container ) + double-quote + +; Here is (part of this ABNF comment), +; an alternative way to specify format strings, +; which captures the extra-grammatical requirement above in the grammar +; but is more complicated: +; +; not-double-quote-or-open-brace = %x0-22 / %x24-7A / %x7C-10FFFF +; +; not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF +; +; format-string-element = not-double-quote-or-open-brace +; / "{" not-double-quote-or-close-brace +; / format-container +; +; format-string = double-quote *format-string-element double-quote +; +; It is not immediately clear which approach is better; there are tradeoffs. +; Regardless, we should choose one eventually. + +; Annotations are built out of names and arguments, which are tokens. +; Two names are currently supported. +; An argument is a sequence of one or more letters, digits, and underscores. + +annotation-name = %s"@context" / %s"@test" + +annotation-argument = 1*( letter / digit / "_" ) + +; A natural (number) is a sequence of one or more digits. +; Note that we allow leading zeros, e.g. '007'. + +natural = 1*digit + +; An integer (number) is either a natural or its negation. +; Note that we also allow leading zeros in negative numbers, e.g. '-007'. + +integer = [ "-" ] natural + +; An untyped literal is just an integer. + +untyped-literal = integer + +; Unsigned literals are naturals followed by unsigned types. + +unsigned-literal = natural ( %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" ) + +; Signed literals are integers followed by signed types. + +signed-literal = integer ( %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" ) + +; Field literals are integers followed by the type of field elements. + +field-literal = integer %s"field" + +; There are two kinds of group literals. +; One is a single integer followed by the type of group elements, +; which denotes the scalar product of the generator point by the integer. +; The other is a pair of integer coordinates, +; which are reduced modulo the prime to identify a point, +; which must be on the elliptic curve. +; It is also allowed to omit one (not both) coordinates, +; with an indication of how to infer the missing coordinate +; (i.e. sign high, sign low, or inferred). + +product-group-literal = integer %s"group" + +group-coordinate = integer / "+" / "-" / "_" + +affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" + +group-literal = product-group-literal / affine-group-literal + +; Note that the rule for group literals above +; allows no whitespace between coordinates. +; If we want to allow whitespace, +; e.g. '(3, 4)group' as opposed to requiring '(3,4)group', +; then we should define affine group literals +; in the syntactic grammar instead of in the lexical grammar. +; We should have a notion of atomic literal in the lexical grammar, +; and (non-atomic) literal in the syntactic grammar. +; The lexical grammar should define a token for ')group' +; if we want no whitespace between the closing parenthesis and 'group'. +; More precisely, the rule for 'literal' below in the lexical grammar +; would be replaced with +; +; atomic-literal = ... / product-group-literal +; +; where the '...' stands for all the '...-literal' alternatives +; in the current rule for 'literal' below, except 'group-literal'. +; Furthermore, the rule for 'symbol' below in the lexical grammar +; would be extended to +; +; symbol = ... / %s")group" +; +; where '...' stands for the current definiens of the rule. +; We would also have to adjust the rule for 'token' below in the lexical grammar +; to reference 'atomic-literal' instead of 'literal' in the definiens. +; We would then add to the syntactic grammar the following rules +; +; affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" +; +; literal = atomic-literal / affine-group-literal +; +; which would now define literals in the syntactic grammar. +; Note that now an affine group literal would have the form +; +; ( , )group +; +; where is optional whitespace; +; however, no whitespace is allowed between the closing ')' and 'group'. + +; Boolean literals are the usual two. + +boolean-literal = %s"true" / %s"false" + +; An address literal is an address wrapped into an indication of address, +; to differentiate it from an identifier. + +address-literal = %s"address" "(" address ")" + +; The ones above are all the literals, as defined by the following rule. + +literal = untyped-literal + / unsigned-literal + / signed-literal + / field-literal + / group-literal + / boolean-literal + / address-literal + +; After defining the (mostly) alphanumeric tokens above, +; it remains to define tokens for non-alphanumeric symbols such as "+" and "(". +; Different programming languages used different terminologies for these, +; e.g. operators, separators, punctuators, etc. +; Here we use 'symbol', for all of them, but we can do something different. +; We could give names to all of these symbols, +; via rules such as +; +; equality-operator = "==" +; +; and defining 'symbol' in terms of those +; +; symbol = ... / equality-operator / ... +; +; This may or may not make the grammar more readable, +; but it would help establish a terminology in the grammar, +; namely the exact names of some of these token. +; On the other hand, at least some of them are perhaps simple enough +; that they could be just described in terms of their symbols, +; e.g. 'double dot', 'question mark', etc. + +symbol = "!" / "&&" / "||" + / "==" / "!=" + / "<" / "<=" / ">" / ">=" + / "+" / "-" / "*" / "/" / "**" + / "=" / "+=" / "-=" / "*=" / "/=" / "**=" + / "(" / ")" + / "[" / "]" + / "{" / "}" + / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" + / "->" + +; Everything defined above, other than comments and whitespace, +; is a token, as defined by the following rule. + +token = keyword + / identifier + / literal + / package-name + / format-string + / annotation-name + / annotation-argument + / symbol + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Syntactic Grammar +; ----------------- + +; The processing defined by the lexical grammar above +; turns the initial sequence of characters +; into a sequence of tokens, comments, and whitespaces. +; The purpose of comments and whitespaces, from a syntactic point of view, +; is just to separate tokens: +; they are discarded, leaving a sequence of tokens. +; The syntactic grammar describes how to turn +; a sequence of tokens into concrete syntax trees. + +; There are unsigned and signed integer types, for five sizes. + +unsigned-type = %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" + +signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" + +integer-type = unsigned-type / signed-type + +; The integer types, along with the field and group types, +; for the arithmetic types, i.e. the ones that support arithmetic operations. + +field-type = %s"field" + +group-type = %s"group" + +arithmetic-type = integer-type / field-type / group-type + +; The arithmetic types, along with the boolean and address types, +; form the scalar types, i.e. the ones whose values do not contain (sub)values. + +boolean-type = %s"bool" + +address-type = %s"address" + +scalar-type = boolean-type / arithmetic-type / address-type + +; Circuit types are denoted by identifiers and the keyword 'Self'. +; The latter is only allowed inside a circuit definition, +; to denote the defined circuit. + +self-type = %s"Self" + +circuit-type = identifier / self-type + +; A tuple type consists of zero, two, or more component types. + +tuple-type = "(" [ type 1*( "," type ) ] ")" + +; An array type consists of an element type +; and an indication of dimensions. +; There is either a single dimension (a number), +; or a tuple of one or more dimensions +; (we could restrict the latter to two or more dimensions). + +array-type = "[" type ";" array-dimensions "]" + +array-dimensions = natural + / "(" natural *( "," natural ) ")" + +; Circuit, tuple, and array types form the aggregate types, +; i.e. types whose values contain (sub)values +; (with the corner-case exception of the empty tuple value). + +aggregate-type = tuple-type / array-type / circuit-type + +; Scalar and aggregate types form all the types. + +type = scalar-type / aggregate-type + +; As often done in grammatical language syntax specifications, +; we define rules for different kinds of expressions, +; which also defines the relative precedence +; of operators and other expression constructs, +; and the (left or right) associativity of binary operators. + +; The primary expressions are self-contained in a way, +; i.e. they have clear deliminations. +; Some consist of single tokens: +; identifiers, the keywords 'self' and 'input', and literals. +; Primary expressions also include parenthesized expressions, +; i.e. any expression may be turned into a primary one +; by putting parentheses around it. +; The other kinds are defined and explained below. + +primary-expression = identifier + / %s"self" + / %s"input" + / literal + / "(" expression ")" + / tuple-expression + / array-expression + / circuit-expression + / function-call + +; There are tuple expressions to construct and deconstruct tuples. +; A construction consists of zero, two, or more component expressions. +; A deconstruction uses a component index (zero-indexed). +; Note that constructions are delimited by closing parentheses +; and deconstructions are delimited by natural tokens. +; The rule below, and similar rules for other aggregate types, +; use the perhaps more familiar 'access', +; but note that 'deconstruction' has a nice symmetry to 'construction'; +; the term 'destructor' has a different meaning in other languages, +; so we may want to avoid it, but not necessarily. + +tuple-construction = "(" [ expression 1*( "," expression ) ] ")" + +tuple-access = primary-expression "." natural + +tuple-expression = tuple-construction / tuple-access + +; The are array expressions to construct and deconstruct arrays. +; There are two kinds of constructions: +; one lists the element expressions (at least one), +; including spreads (via '...') which are arrays being spliced in; +; the other repeats (the value of) a single expression +; across one or more dimensions. +; There are two kinds of deconstructions: +; one selects a single element by index (zero-indexed); +; the other selects a range via two indices, +; the first inclusive and the second exclusive -- +; both are optional, +; the first defaulting to 0 and the second to the array length. +; Note that these expressions are all delimited +; by closing square brackets. + +array-inline-construction = "[" + array-inline-element + *( "," array-inline-element ) + "]" + +array-inline-element = expression / "..." expression + +array-repeat-construction = "[" expression ";" array-dimensions "]" + +array-construction = array-inline-construction / array-repeat-construction + +array-element-access = primary-expression "[" expression "]" + +array-range-access = primary-expression "[" [expression] ".." [expression] "]" + +array-access = array-element-access / array-range-access + +array-expression = array-construction / array-access + +; There are circuit expressions to construct and deconstruct circuit values. +; A construction lists values for all the member variables (in any order); +; there must be at least one member variable currently. +; A deconstruction selects a member variable by name. +; Note that these expressions are delimited, +; by closing curly braces or identifiers. + +circuit-construction = circuit-type "{" + circuit-inline-element *( "," circuit-inline-element ) + "}" + +circuit-inline-element = identifier ":" expression + +circuit-access = primary-expression "." identifier + +circuit-expression = circuit-construction / circuit-access + +; There are three kinds of function calls: +; top-level function calls, +; instance (i.e. non-static) member function calls, and +; static member function calls. +; What changes is the start, but they all end in an argument list, +; delimited by a closing parenthesis. + +top-level-function-call = identifier function-arguments + +instance-member-function-call = primary-expression "." + identifier function-arguments + +static-member-function-call = circuit-type "::" identifier function-arguments + +function-call = top-level-function-call + / instance-member-function-call + / static-member-function-call + +function-arguments = "(" [ expression *( "," expression ) ] ")" + +; Unary operators have the highest precedence. +; They apply to primary expressions +; and recursively to unary expressions. + +unary-expression = primary-expression + / "!" unary-expression + / "-" unary-expression + +; Next in the operator precedence is exponentiation, +; following mathematical practice. +; The current rule below makes exponentiation left-associative, +; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. +; This is easy to change if we want it to be right-associative instead. + +exponential-expression = unary-expression + / exponential-expression "**" unary-expression + +; Next in precedence come multiplication and division, both left-associative. + +multiplicative-expression = exponential-expression + / multiplicative-expression "*" exponential-expression + / multiplicative-expression "/" exponential-expression + +; Then there are addition and subtraction, both left-assocative. + +additive-expression = multiplicative-expression + / additive-expression "+" multiplicative-expression + / additive-expression "-" multiplicative-expression + +; Next in the precedence order are ordering relations. +; These are not associative, because they return boolean values. + +ordering-expression = additive-expression + / additive-expression "<" additive-expression + / additive-expression ">" additive-expression + / additive-expression "<=" additive-expression + / additive-expression ">=" additive-expression + +; Equalities return booleans but may also operate on boolean, +; so we make them left-associative. + +equality-expression = ordering-expression + / equality-expression "==" ordering-expression + / equality-expression "!=" ordering-expression + +; Next come conjunctive expressions, left-associative. + +conjunctive-expression = equality-expression + / conjunctive-expression "&&" equality-expression + +; Next come disjunctive expressions, left-associative. + +disjunctive-expression = conjunctive-expression + / disjunctive-expression "||" conjunctive-expression + +; Finally we have conditional expressions. + +conditional-expression = disjunctive-expression + / conditional-expression + "?" expression + ":" conditional-expression + +; These are all the expressions. +; Recall that conditional expressions +; may be disjunctive expressions, +; which may be conjunctive expressions, +; and so on all the way to primary expressions. + +expression = conditional-expression + +; There are various kinds of statements, +; including blocks, which are +; possibly empty sequences of statements surounded by curly braces. + +statement = expression-statement + / return-statement + / variable-definition-statement + / conditional-statement + / loop-statement + / assignment-statement + / console-statement + / block + +block = "{" *statement "}" + +; An expression (that returns the empty tuple) +; can be turned into a statement by appending a semicolon. + +expression-statement = expression ";" + +; A return statement always takes an expression, +; and does not end with a semicolon (but we may want to change that). + +return-statement = %s"return" expression + +; There are two kinds of variable definition statements, +; which only differ in the starting keyword. +; The variables are either a single one or a tuple of two or more; +; in all cases, there is just one optional type +; and just one initializing expression. + +variable-definition-statement = ( %s"let" / %s"const" ) + identifier-or-identifiers + [ ":" type ] "=" expression ";" + +identifier-or-identifiers = identifier + / "(" identifier 1*( "," identifier ) ")" + +; A conditional statement always starts with a condition and a block +; (which together form a branch). +; It may stop there, or it may continue with an alternative block, +; or possibly with another conditional statement, forming a chain. +; Note that we require blocks in all branches, not merely statements. + +branch = %s"if" expression block + +conditional-statement = branch + / branch %s"else" block + / branch %s"else" conditional-statement + +; A loop statement implicitly defines a loop variable +; that goes from a starting value (inclusive) to an ending value (exclusive). +; The body is a block. + +loop-statement = %s"for" identifier %s"in" expression ".." expression block + +; An assignment statement is straightforward. +; Based on the operator, the assignment may be simple (i.e. '=') +; or compound (i.e. combining assignment with an arithmetic operation). + +assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" + +assignment-statement = expression assignment-operator expression ";" + +; Console statements start with the 'console' keyword, +; followed by a console function call. +; The call may be an assertion or a print command. +; The former takes an expression (which must be boolean) as argument. +; The latter takes either no argument, +; or a format string followed by expressions, +; whose number must match the number of containers '{}' in the format string. +; Note that the console function names are identifiers, not keywords. +; There are three kind of printing. + +console-statement = %s"console" "." console-call + +console-call = assert-call + / print-call + +assert-call = %s"assert" "(" expression ")" + +print-function = %s"debug" / %s"error" / %s"log" + +print-arguments = "(" [ format-string *( "," expression ) ] ")" + +print-call = print-function print-arguments + +; An annotation consists of an annotation name (which starts with '@') +; with optional annotation arguments. +; Note that no parentheses are used if there are no arguments. + +annotation = annotation-name + [ "(" annotation-argument *( "," annotation-argument ) ")" ] + +; A function declaration defines a function. +; This could be called 'function-definition' instead, +; but see the comments about the 'declaration' rule below. +; The output type is optional (it defaults to the empty tuple type). +; In general, a function input consists of an identifier and a type, +; with an optional 'const' modifier. +; However, functions inside circuits +; may start with a 'mut self' or 'self' parameter, +; which may be the only parameter in fact. +; Furthermore, any function may end with an 'input' parameter, +; which may be the only parameter in fact. + +function-declaration = *annotation %s"function" identifier + "(" [ function-parameters ] ")" [ "->" type ] + block + +function-parameters = self-parameter [ "," input-parameter ] + / self-parameter "," function-inputs [ "," input-parameter ] + / function-inputs [ "," input-parameter ] + / input-parameter + +self-parameter = [%s"mut"] %s"self" + +function-inputs = function-input *( "," function-input ) + +function-input = [ %s"const" ] identifier ":" type + +input-parameter = %s"input" + +; A circuit member variable declaration consists of an identifier and a type. +; A circuit member function declaration consists of a function declaration. +; We could call these 'member-definition' etc., +; but see the comments about the 'declaration' rule below. + +member-declaration = member-variable-declaration + / member-function-declaration + +member-variable-declaration = identifier ":" type + +member-function-declaration = function-declaration + +; A circuit declaration defines a circuit type. It is straightforward. +; This could be called 'circuit-definition' instead, +; but see the comments about the 'declaration' rule below. + +circuit-declaration = *annotation %s"circuit" identifier + "{" member-declaration *( "," member-declaration ) "}" + +; An import declaration consists of the 'import' keyword +; followed by a package path, which may be one of the following: +; a single wildcard; +; an identifier, optionally followed by a local renamer; +; a package name followed by a path, recursively; +; or a parenthesized list of package paths, +; which are "fan out" of the initial path. +; Note that we allow the last element of the parenthesized list +; to be followed by a comma, presumably for convenience. + +import-declaration = %s"import" package-path + +package-path = "*" + / identifier [ %s"as" identifier ] + / package-name "." package-path + / "(" package-path *( "," package-path ) [","] ")" + +; Finally, we define a file as a sequence of zero or more declarations. +; This is why we used 'function-declaration' and 'circuit-declaration' +; instead of 'function-definition' and 'ciruit-definition': +; this way, they are all declarations of some sort. +; An import declaration cannot really called an import definition, +; because it does not define anything. +; But we may revisit this, and use 'definition' instead of 'declaration'. + +declaration = import-declaration + / function-declaration + / circuit-declaration + +file = *declaration From bac54b21de589d02a0e5fcf37c9058d3c4acfaa6 Mon Sep 17 00:00:00 2001 From: gluax Date: Mon, 22 Mar 2021 15:12:33 -0400 Subject: [PATCH 003/108] make sure we keep crlf for abnf grammar file --- grammar/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 grammar/.gitattributes diff --git a/grammar/.gitattributes b/grammar/.gitattributes new file mode 100644 index 0000000000..0d7e2876d4 --- /dev/null +++ b/grammar/.gitattributes @@ -0,0 +1 @@ +abnf-grammar.txt text eol=crlf \ No newline at end of file From d14edcb4cd248d626e4da9cd94682a4f1a37a24a Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 23 Mar 2021 11:21:52 +0100 Subject: [PATCH 004/108] refactor: use a macro to deduplicate code in Integer::allocate_type Signed-off-by: ljedrz --- compiler/src/value/integer/integer.rs | 151 ++------------------------ compiler/src/value/integer/macros.rs | 26 +++++ 2 files changed, 36 insertions(+), 141 deletions(-) diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index 40368405ec..e35d6a4dfd 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -146,148 +146,17 @@ impl Integer { span: &Span, ) -> Result { Ok(match integer_type { - IntegerType::U8 => { - let u8_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); + IntegerType::U8 => allocate_type!(u8, UInt8, Integer::U8, cs, name, option, span), + IntegerType::U16 => allocate_type!(u16, UInt16, Integer::U16, cs, name, option, span), + IntegerType::U32 => allocate_type!(u32, UInt32, Integer::U32, cs, name, option, span), + IntegerType::U64 => allocate_type!(u64, UInt64, Integer::U64, cs, name, option, span), + IntegerType::U128 => allocate_type!(u128, UInt128, Integer::U128, cs, name, option, span), - let u8_result = UInt8::alloc( - cs.ns(|| format!("`{}: u8` {}:{}", name, span.line_start, span.col_start)), - || u8_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: u8", name), span))?; - - Integer::U8(u8_result) - } - IntegerType::U16 => { - let u16_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let u16_result = UInt16::alloc( - cs.ns(|| format!("`{}: u16` {}:{}", name, span.line_start, span.col_start)), - || u16_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: u16", name), span))?; - - Integer::U16(u16_result) - } - IntegerType::U32 => { - let u32_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let u32_result = UInt32::alloc( - cs.ns(|| format!("`{}: u32` {}:{}", name, span.line_start, span.col_start)), - || u32_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: u32", name), span))?; - - Integer::U32(u32_result) - } - IntegerType::U64 => { - let u64_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let u64_result = UInt64::alloc( - cs.ns(|| format!("`{}: u64` {}:{}", name, span.line_start, span.col_start)), - || u64_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: u64", name), span))?; - - Integer::U64(u64_result) - } - IntegerType::U128 => { - let u128_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let u128_result = UInt128::alloc( - cs.ns(|| format!("`{}: u128` {}:{}", name, span.line_start, span.col_start)), - || u128_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: u128", name), span))?; - - Integer::U128(u128_result) - } - - IntegerType::I8 => { - let i8_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let i8_result = Int8::alloc( - cs.ns(|| format!("`{}: i8` {}:{}", name, span.line_start, span.col_start)), - || i8_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: i8", name), span))?; - - Integer::I8(i8_result) - } - IntegerType::I16 => { - let i16_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let i16_result = Int16::alloc( - cs.ns(|| format!("`{}: i16` {}:{}", name, span.line_start, span.col_start)), - || i16_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: i16", name), span))?; - - Integer::I16(i16_result) - } - IntegerType::I32 => { - let i32_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let i32_result = Int32::alloc( - cs.ns(|| format!("`{}: i32` {}:{}", name, span.line_start, span.col_start)), - || i32_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: i32", name), span))?; - - Integer::I32(i32_result) - } - IntegerType::I64 => { - let i64_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let i64_result = Int64::alloc( - cs.ns(|| format!("`{}: i64` {}:{}", name, span.line_start, span.col_start)), - || i64_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: i64", name), span))?; - - Integer::I64(i64_result) - } - IntegerType::I128 => { - let i128_option = option.map(|s| { - s.parse::() - .map_err(|_| IntegerError::invalid_integer(s, span)) - .unwrap() - }); - let i128_result = Int128::alloc( - cs.ns(|| format!("`{}: i128` {}:{}", name, span.line_start, span.col_start)), - || i128_option.ok_or(SynthesisError::AssignmentMissing), - ) - .map_err(|_| IntegerError::missing_integer(format!("{}: i128", name), span))?; - - Integer::I128(i128_result) - } + IntegerType::I8 => allocate_type!(i8, Int8, Integer::I8, cs, name, option, span), + IntegerType::I16 => allocate_type!(i16, Int16, Integer::I16, cs, name, option, span), + IntegerType::I32 => allocate_type!(i32, Int32, Integer::I32, cs, name, option, span), + IntegerType::I64 => allocate_type!(i64, Int64, Integer::I64, cs, name, option, span), + IntegerType::I128 => allocate_type!(i128, Int128, Integer::I128, cs, name, option, span), }) } diff --git a/compiler/src/value/integer/macros.rs b/compiler/src/value/integer/macros.rs index 932a646fa4..5b67c9429b 100644 --- a/compiler/src/value/integer/macros.rs +++ b/compiler/src/value/integer/macros.rs @@ -153,3 +153,29 @@ macro_rules! match_integers_span { } }; } + +macro_rules! allocate_type { + ($rust_ty:ty, $gadget_ty:ty, $leo_ty:path, $cs:expr, $name:expr, $option:expr, $span:expr) => {{ + let option = $option.map(|s| { + s.parse::<$rust_ty>() + .map_err(|_| IntegerError::invalid_integer(s, $span)) + .unwrap() + }); + + let result = <$gadget_ty>::alloc( + $cs.ns(|| { + format!( + "`{}: {}` {}:{}", + $name, + stringify!($rust_ty), + $span.line_start, + $span.col_start + ) + }), + || option.ok_or(SynthesisError::AssignmentMissing), + ) + .map_err(|_| IntegerError::missing_integer(format!("{}: {}", $name, stringify!($rust_ty)), $span))?; + + $leo_ty(result) + }}; +} From 1adc8cee140081cb89b34275efde41e8ae7ccb84 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 12:11:42 -0400 Subject: [PATCH 005/108] consistent keyword order and names --- grammar/abnf-grammar.txt | 2178 ++++++++++++++++----------------- parser/src/tokenizer/lexer.rs | 26 +- parser/src/tokenizer/token.rs | 35 +- 3 files changed, 1120 insertions(+), 1119 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index ff93d19c09..98ab3d56a6 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -1,1089 +1,1089 @@ -; Leo Library -; -; Copyright (C) 2021 Aleo Systems Inc. -; -; Author: Alessandro Coglio (acoglio on GitHub) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Format Note -; ----------- - -; The ABNF standard requires grammars to consist of lines terminated by CR LF -; (i.e. carriage return followed by line feed, DOS/Windows-style), -; as explained in the background on ABNF later in this file. -; This file's lines are therefore terminated by CR LF. -; To avoid losing this requirement across systems, -; this file is marked as 'text eol=crlf' in .gitattributes: -; this means that the file is textual, enabling visual diffs, -; but its lines will always be terminated by CR LF on any system. - -; Note that this CR LF requirement only applies to the grammar files themselves. -; It does not apply to the lines of the languages described by the grammar. -; ABNF grammar may describe any kinds of languages, -; with any kind of line terminators, -; or even without line terminators at all (e.g. for "binary" languages). - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Introduction -; ------------ - -; This file contains an initial draft of -; a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. -; Background on ABNF is provided later in this file. - -; The initial motivation for creating an ABNF grammar of Leo was that -; we have a formally verified parser of ABNF grammars -; (at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; -; also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) -; which we have used to parse this ABNF grammar of Leo -; into a formal representation, in the ACL2 theorem prover, -; of the Leo concrete syntax. -; The parsing of this grammar file into an ACL2 representation -; happens every time the ACL2 formalization of Leo is built. - -; In addition to that initial motivation, -; this ABNF grammar has now the additional and primary purpose of -; providing an official definition of the syntax of Leo -; that is both human-readable and machine-readable. -; This grammar will be part of the (upcoming) Leo language reference, -; of the Leo Language Formal Specification -; (i.e. the LaTeX document in the leo-semantics repo), -; and of the ACL2 formalization of Leo (which was the initial motivation). -; It has also been suggested that it may be used to generate tests. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Background on ABNF -; ------------------ - -; ABNF is an Internet standard: -; see https://www.rfc-editor.org/info/rfc5234 -; and https://www.rfc-editor.org/info/rfc7405. -; It is used to specify the syntax of JSON, HTTP, and other standards. - -; The following is copied (and "un-LaTeX'd") from the aforementioned paper -; (at https://www.kestrel.edu/people/coglio/vstte18.pdf). - -; ABNF adds conveniences and makes slight modifications -; to Backus-Naur Form (BNF), -; without going beyond context-free grammars. - -; Instead of BNF's angle-bracket notation for nonterminals, -; ABNF uses case-insensitive names consisting of letters, digits, and dashes, -; e.g. HTTP-message and IPv6address. -; ABNF includes an angle-bracket notation for prose descriptions, -; e.g. , -; usable as last resort in the definiens of a nonterminal. - -; While BNF allows arbitrary terminals, -; ABNF uses only natural numbers as terminals, -; and denotes them via: -; (i) binary, decimal, or hexadecimal sequences, -; e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A -; all denote the string '1 3 10'; -; (ii) binary, decimal, or hexadecimal ranges, -; e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 -; (an ASCII digit); -; (iii) case-sensitive ASCII strings, -; e.g. %s"Ab" denotes the string '65 98'; -; and (iv) case-insensitive ASCII strings, -; e.g. %i"ab", or just "ab", denotes -; any string among -; '65 66', -; '65 98', -; '97 66', and -; '97 98'. -; ABNF terminals in suitable sets represent ASCII or Unicode characters. - -; ABNF allows repetition prefixes n*m, -; where n and m are natural numbers in decimal notation; -; if absent, -; n defaults to 0, and -; m defaults to infinity. -; For example, -; 1*4HEXDIG denotes one to four HEXDIGs, -; *3DIGIT denotes up to three DIGITs, and -; 1*OCTET denotes one or more OCTETs. -; A single n prefix -; abbreviates n*n, -; e.g. 3DIGIT denotes three DIGITs. - -; Instead of BNF's |, ABNF uses / to separate alternatives. -; Repetition prefixes have precedence over juxtapositions, -; which have precedence over /. -; Round brackets group things and override the aforementioned precedence rules, -; e.g. *(WSP / CRLF WSP) denotes strings -; obtained by repeating, zero or more times, -; either (i) a WSP or (ii) a CRLF followed by a WSP. -; Square brackets also group things but make them optional, -; e.g. [":" port] is equivalent to 0*1(":" port). - -; Instead of BNF's ::=, ABNF uses = to define nonterminals, -; and =/ to incrementally add alternatives -; to previously defined nonterminals. -; For example, the rule BIT = "0" / "1" -; is equivalent to BIT = "0" followed by BIT =/ "1". - -; The syntax of ABNF itself is formally specified in ABNF -; (in Section 4 of the aforementioned RFC 5234, -; after the syntax and semantics of ABNF -; are informally specified in natural language -; (in Sections 1, 2, and 3 of the aforementioned RFC 5234). -; The syntax rules of ABNF prescribe the ASCII codes allowed for -; white space (spaces and horizontal tabs), -; line endings (carriage returns followed by line feeds), -; and comments (semicolons to line endings). - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Structure -; --------- - -; Language specifications often define the syntax of their languages via -; (i) a lexical grammar that describes how -; sequence of characters are parsed into tokens, and -; (ii) a syntactic grammar that described how -; tokens are parsed into expressions, statements, etc. -; (The adjectives 'lexical' and 'syntactic' are -; the ones used in the Java language specification; -; other terms may be used by other languages, -; but the essence is similar.) -; The situation is sometimes more complex, -; with multiple passes (e.g. Unicode escape processing in Java), -; but the division between lexical and syntactic (in the sense above) stands. - -; In the aforementioned language specifications, -; both the lexical and syntactic grammars -; are normally written in a context-free grammar notation, -; augmented with natural language that may assert, for instance, -; that tokenization always takes the longest sequence that constitutes a token. - -; This dual structure appears to be motivated by the fact that -; concerns of white space, line endings, etc. -; can be handled by the lexical grammar, -; allowing the syntactic grammar to focus on the more important structure. -; Handling both aspects in a single context-free grammar may be unwieldy, -; so having two grammars provides more clarity and readability. - -; In contrast, PEG (Parsing Expression Grammar) formalisms like Pest -; naturally embody a procedural interpretation -; that can handle white space and tokenization in just one manageable grammar. -; However, this procedural interpretaion may be sometimes -; less clear and readable to humans than context-free rules. -; Indeed, context-free grammar are commonly used to documentat languages. - -; ABNF is a context-free grammar notation, -; with no procedural interpretation, -; and therefore it makes sense to define -; separate lexical and syntactic ABNF grammars for Leo. -; Conceptually, the two grammars define two subsequent processing phases, -; as detailed below. -; However, a parser implementation does not need to perform -; two strictly separate phases (in fact, it typically does not), -; so long as it produces the same final result. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Operator Precedence -; ------------------- - -; We formulate the grammar rules for expressions -; in a way that describes the relative precedence of operators, -; as often done in language syntax specifications. - -; For instance, consider the rules -; -; multiplicative-expression = -; exponential-expression -; / multiplicative-expression "*" exponential-expression -; / multiplicative-expression "/" exponential-expression -; -; additive-expression = -; multiplicative-expression -; / additive-expression "+" multiplicative-expression -; / additive-expression "-" multiplicative-expression -; -; this rule tells us that the additive operators '+' and '-' have -; lower precedence than the multiplicative operators '*' and '/', -; and that both the additive and multiplicative operators associate to the left. -; This may be best understood via the examples given below. - -; According to the rules, the expression -; -; x + y * z -; -; can only be parsed as -; -; + -; / \ -; x * -; / \ -; y z -; -; and not as -; -; * -; / \ -; + z -; / \ -; x y -; -; because a multiplicative expression cannot have an additive expression -; as first sub-expression, as it would in the second tree above. - -; Also according to the rules, the expression -; -; x + y + z -; -; can only be parsed as -; -; + -; / \ -; + z -; / \ -; x y -; -; and not as -; -; + -; / \ -; x + -; / \ -; y z -; -; because an additive expression cannot have an additive expression -; as second sub-expression, as it would in the second tree above. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Naming Convention -; ----------------- - -; For this ABNF grammar, we choose nonterminal names -; that consist of complete English words, separated by dashes, -; and that describe the construct the way it is in English. -; For instance, we use the name 'conditional-statement' -; to describe conditional statements. - -; At the same time, we attempt to establish -; a precise and "official" nomenclature for the Leo constructs, -; by way of the nonterminal names that define their syntax. -; For instance, the rule -; -; group-literal = product-group-literal -; / affine-group-literal -; -; tells us that there are two kinds of group literals, -; namely product group literals and affine group literals. -; This is more precise than describing them as -; integers (which are not really group elements per se), -; or points (they are all points, just differently specified), -; or being singletons vs. pairs (which is a bit generic). - -; The only exception to the nomenclature-establishing role of the grammar -; is the fact that, as discussed above, -; we write the grammar rules in a way that determines -; the relative precedence and the associativity of expression operators, -; and that therefore we have rules like -; -; unary-expression = primary-expression -; / "!" unary-expression -; / "-" unary-expression -; -; In order to allow the recursion of the rule to stop, -; we need to regard, in the grammar, a primary expression as a unary expression. -; However, this is just a grammatical artifact: -; ontologically, a primary expression is not really a unary expression, -; because a unary expression is one that consists of -; a unary operator and an operand sub-expression. -; These terminological "exceptions" should be easy to identify in the rules. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Lexical Grammar -; --------------- - -; A Leo file is a finite sequence of Unicode characters, -; represented as Unicode code points, -; which are numbers in the range form 0 to 10FFFFh. -; These are captured by the ABNF rule 'character' below. - -; The lexical grammar defines how, conceptually, -; the sequence of characters is turned into -; a sequence of tokens, comments, and whitespaces. - -; As stated, the lexical grammar is ambiguous. -; For example, the sequence of characters '**' (i.e. two stars) -; could be equally parsed as two '*' symbol tokens or one '**' symbol token -; (see rule for 'symbol' below). -; As another example, the sequence or characters '' -; (i.e. carriage return followed by line feed) -; could be equally parsed as two line terminators or one -; (see rule for 'newline'). - -; Thus, as often done in language syntax definitions, -; the lexical grammar is disambiguated by -; the extra-grammatical requirement that -; the longest possible sequence of characters is always parsed. -; This way, '**' must be parsed as one '**' symbol token, -; and '' must be parsed as one line terminator. -; (We should formalize this requirement, -; along with the other extra-grammatical requirements given below, -; and formally prove that they indeed make -; the lexical grammar of Leo unambiguous.) - -; As mentioned above, a character is any Unicode code point. -; This grammar does not say how those are encoded in files (e.g. UTF-8): -; it starts with a decoded sequence of Unicode code points. -; Note that we allow any value, -; even though some values may not be used according to the Unicode standard. - -character = %x0-10FFFF ; any Unicode code point - -; We give names to certain ASCII characters. - -horizontal-tab = %x9 - -line-feed = %xA - -carriage-return = %xD - -space = %x20 - -double-quote = %x22 - -; We give names to complements of certain ASCII characters. -; These consist of all the Unicode characters except for one or two. - -not-double-quote = %x0-22 / %x24-10FFFF ; anything but " - -not-star = %x0-29 / %x2B-10FFFF ; anything but * - -not-line-feed-or-carriage-return = %x0-9 / %xB-C / %xE-10FFFF - ; anything but LF or CR - -not-star-or-slash = %x0-29 / %x2B-2E / %x30-10FFFF ; anything but * or / - -; Lines in Leo may be terminated via -; a single carriage return, -; a line feed, -; or a carriage return immediately followed by a line feed. -; Note that the latter combination constitutes a single line terminator, -; according to the extra-grammatical rule of the longest sequence. - -newline = line-feed / carriage-return / carriage-return line-feed - -; Line terminators form whitespace, along with spaces and horizontal tabs. - -whitespace = space / horizontal-tab / newline - -; There are two kinds of comments in Leo, as in other languages. -; One is block comments of the form '/* ... */', -; and the other is end-of-line comments '// ...'. -; The first kind start at '/*' and end at the first '*/', -; possibly spanning multiple (partial) lines; -; they do no nest. -; The second kind start at '//' and extend till the end of the line. -; The rules about comments given below are similar to -; the ones used in the Java language specification. - -comment = block-comment / end-of-line-comment - -block-comment = "/*" rest-of-block-comment - -rest-of-block-comment = "*" rest-of-block-comment-after-star - / not-star rest-of-block-comment - -rest-of-block-comment-after-star = "/" - / "*" rest-of-block-comment-after-star - / not-star-or-slash rest-of-block-comment - -end-of-line-comment = "//" *not-line-feed-or-carriage-return newline - -; Below are the keywords in the Leo language. -; They cannot be used as identifiers. - -keyword = %s"address" - / %s"as" - / %s"bool" - / %s"circuit" - / %s"console" - / %s"const" - / %s"else" - / %s"false" - / %s"field" - / %s"for" - / %s"function" - / %s"group" - / %s"i8" - / %s"i16" - / %s"i32" - / %s"i64" - / %s"i128" - / %s"if" - / %s"import" - / %s"in" - / %s"input" - / %s"let" - / %s"mut" - / %s"return" - / %s"Self" - / %s"self" - / %s"static" - / %s"string" - / %s"true" - / %s"u8" - / %s"u16" - / %s"u32" - / %s"u64" - / %s"u128" - -; The following rules define (ASCII) digits -; and (uppercase and lowercase) letters. - -digit = %x30-39 ; 0-9 - -uppercase-letter = %x41-5A ; A-Z - -lowercase-letter = %x61-7A ; a-z - -letter = uppercase-letter / lowercase-letter - -; An identifier is a non-empty sequence of letters, digits, and underscores, -; starting with a letter. -; It must not be a keyword: this is an extra-grammatical constraint. - -identifier = letter *( letter / digit / "_" ) ; but not a keyword - -; A package name consists of one or more segments separated by single dashes, -; where each segment is a non-empty sequence of lowercase letters and digits. - -package-name = 1*( lowercase-letter / digit ) - *( "-" 1*( lowercase-letter / digit ) ) - -; An address starts with 'aleo1' -; and continues with exactly 58 lowercase letters and digits. -; Thus an address always consists of 63 characters. - -address = %s"aleo1" 58( lowercase-letter / digit ) - -; A format string is a sequence of characters, other than double quote, -; surrounded by double quotes. -; Within a format string, substrings '{}' are distinguished as containers -; (these are the ones that may be matched with values -; whose textual representation replaces the containers -; in the printed string). -; There is an implicit extra-grammatical requirements that -; the explicit 'format-container' instances include -; all the occurrences of '{}' in the parsed character sequence: -; that is, there may not be two contiguous 'not-double-quote' instances -; that are '{' and '}'. - -format-string-container = "{}" - -format-string = double-quote - *( not-double-quote / format-string-container ) - double-quote - -; Here is (part of this ABNF comment), -; an alternative way to specify format strings, -; which captures the extra-grammatical requirement above in the grammar -; but is more complicated: -; -; not-double-quote-or-open-brace = %x0-22 / %x24-7A / %x7C-10FFFF -; -; not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF -; -; format-string-element = not-double-quote-or-open-brace -; / "{" not-double-quote-or-close-brace -; / format-container -; -; format-string = double-quote *format-string-element double-quote -; -; It is not immediately clear which approach is better; there are tradeoffs. -; Regardless, we should choose one eventually. - -; Annotations are built out of names and arguments, which are tokens. -; Two names are currently supported. -; An argument is a sequence of one or more letters, digits, and underscores. - -annotation-name = %s"@context" / %s"@test" - -annotation-argument = 1*( letter / digit / "_" ) - -; A natural (number) is a sequence of one or more digits. -; Note that we allow leading zeros, e.g. '007'. - -natural = 1*digit - -; An integer (number) is either a natural or its negation. -; Note that we also allow leading zeros in negative numbers, e.g. '-007'. - -integer = [ "-" ] natural - -; An untyped literal is just an integer. - -untyped-literal = integer - -; Unsigned literals are naturals followed by unsigned types. - -unsigned-literal = natural ( %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" ) - -; Signed literals are integers followed by signed types. - -signed-literal = integer ( %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" ) - -; Field literals are integers followed by the type of field elements. - -field-literal = integer %s"field" - -; There are two kinds of group literals. -; One is a single integer followed by the type of group elements, -; which denotes the scalar product of the generator point by the integer. -; The other is a pair of integer coordinates, -; which are reduced modulo the prime to identify a point, -; which must be on the elliptic curve. -; It is also allowed to omit one (not both) coordinates, -; with an indication of how to infer the missing coordinate -; (i.e. sign high, sign low, or inferred). - -product-group-literal = integer %s"group" - -group-coordinate = integer / "+" / "-" / "_" - -affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" - -group-literal = product-group-literal / affine-group-literal - -; Note that the rule for group literals above -; allows no whitespace between coordinates. -; If we want to allow whitespace, -; e.g. '(3, 4)group' as opposed to requiring '(3,4)group', -; then we should define affine group literals -; in the syntactic grammar instead of in the lexical grammar. -; We should have a notion of atomic literal in the lexical grammar, -; and (non-atomic) literal in the syntactic grammar. -; The lexical grammar should define a token for ')group' -; if we want no whitespace between the closing parenthesis and 'group'. -; More precisely, the rule for 'literal' below in the lexical grammar -; would be replaced with -; -; atomic-literal = ... / product-group-literal -; -; where the '...' stands for all the '...-literal' alternatives -; in the current rule for 'literal' below, except 'group-literal'. -; Furthermore, the rule for 'symbol' below in the lexical grammar -; would be extended to -; -; symbol = ... / %s")group" -; -; where '...' stands for the current definiens of the rule. -; We would also have to adjust the rule for 'token' below in the lexical grammar -; to reference 'atomic-literal' instead of 'literal' in the definiens. -; We would then add to the syntactic grammar the following rules -; -; affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" -; -; literal = atomic-literal / affine-group-literal -; -; which would now define literals in the syntactic grammar. -; Note that now an affine group literal would have the form -; -; ( , )group -; -; where is optional whitespace; -; however, no whitespace is allowed between the closing ')' and 'group'. - -; Boolean literals are the usual two. - -boolean-literal = %s"true" / %s"false" - -; An address literal is an address wrapped into an indication of address, -; to differentiate it from an identifier. - -address-literal = %s"address" "(" address ")" - -; The ones above are all the literals, as defined by the following rule. - -literal = untyped-literal - / unsigned-literal - / signed-literal - / field-literal - / group-literal - / boolean-literal - / address-literal - -; After defining the (mostly) alphanumeric tokens above, -; it remains to define tokens for non-alphanumeric symbols such as "+" and "(". -; Different programming languages used different terminologies for these, -; e.g. operators, separators, punctuators, etc. -; Here we use 'symbol', for all of them, but we can do something different. -; We could give names to all of these symbols, -; via rules such as -; -; equality-operator = "==" -; -; and defining 'symbol' in terms of those -; -; symbol = ... / equality-operator / ... -; -; This may or may not make the grammar more readable, -; but it would help establish a terminology in the grammar, -; namely the exact names of some of these token. -; On the other hand, at least some of them are perhaps simple enough -; that they could be just described in terms of their symbols, -; e.g. 'double dot', 'question mark', etc. - -symbol = "!" / "&&" / "||" - / "==" / "!=" - / "<" / "<=" / ">" / ">=" - / "+" / "-" / "*" / "/" / "**" - / "=" / "+=" / "-=" / "*=" / "/=" / "**=" - / "(" / ")" - / "[" / "]" - / "{" / "}" - / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" - / "->" - -; Everything defined above, other than comments and whitespace, -; is a token, as defined by the following rule. - -token = keyword - / identifier - / literal - / package-name - / format-string - / annotation-name - / annotation-argument - / symbol - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; Syntactic Grammar -; ----------------- - -; The processing defined by the lexical grammar above -; turns the initial sequence of characters -; into a sequence of tokens, comments, and whitespaces. -; The purpose of comments and whitespaces, from a syntactic point of view, -; is just to separate tokens: -; they are discarded, leaving a sequence of tokens. -; The syntactic grammar describes how to turn -; a sequence of tokens into concrete syntax trees. - -; There are unsigned and signed integer types, for five sizes. - -unsigned-type = %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" - -signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" - -integer-type = unsigned-type / signed-type - -; The integer types, along with the field and group types, -; for the arithmetic types, i.e. the ones that support arithmetic operations. - -field-type = %s"field" - -group-type = %s"group" - -arithmetic-type = integer-type / field-type / group-type - -; The arithmetic types, along with the boolean and address types, -; form the scalar types, i.e. the ones whose values do not contain (sub)values. - -boolean-type = %s"bool" - -address-type = %s"address" - -scalar-type = boolean-type / arithmetic-type / address-type - -; Circuit types are denoted by identifiers and the keyword 'Self'. -; The latter is only allowed inside a circuit definition, -; to denote the defined circuit. - -self-type = %s"Self" - -circuit-type = identifier / self-type - -; A tuple type consists of zero, two, or more component types. - -tuple-type = "(" [ type 1*( "," type ) ] ")" - -; An array type consists of an element type -; and an indication of dimensions. -; There is either a single dimension (a number), -; or a tuple of one or more dimensions -; (we could restrict the latter to two or more dimensions). - -array-type = "[" type ";" array-dimensions "]" - -array-dimensions = natural - / "(" natural *( "," natural ) ")" - -; Circuit, tuple, and array types form the aggregate types, -; i.e. types whose values contain (sub)values -; (with the corner-case exception of the empty tuple value). - -aggregate-type = tuple-type / array-type / circuit-type - -; Scalar and aggregate types form all the types. - -type = scalar-type / aggregate-type - -; As often done in grammatical language syntax specifications, -; we define rules for different kinds of expressions, -; which also defines the relative precedence -; of operators and other expression constructs, -; and the (left or right) associativity of binary operators. - -; The primary expressions are self-contained in a way, -; i.e. they have clear deliminations. -; Some consist of single tokens: -; identifiers, the keywords 'self' and 'input', and literals. -; Primary expressions also include parenthesized expressions, -; i.e. any expression may be turned into a primary one -; by putting parentheses around it. -; The other kinds are defined and explained below. - -primary-expression = identifier - / %s"self" - / %s"input" - / literal - / "(" expression ")" - / tuple-expression - / array-expression - / circuit-expression - / function-call - -; There are tuple expressions to construct and deconstruct tuples. -; A construction consists of zero, two, or more component expressions. -; A deconstruction uses a component index (zero-indexed). -; Note that constructions are delimited by closing parentheses -; and deconstructions are delimited by natural tokens. -; The rule below, and similar rules for other aggregate types, -; use the perhaps more familiar 'access', -; but note that 'deconstruction' has a nice symmetry to 'construction'; -; the term 'destructor' has a different meaning in other languages, -; so we may want to avoid it, but not necessarily. - -tuple-construction = "(" [ expression 1*( "," expression ) ] ")" - -tuple-access = primary-expression "." natural - -tuple-expression = tuple-construction / tuple-access - -; The are array expressions to construct and deconstruct arrays. -; There are two kinds of constructions: -; one lists the element expressions (at least one), -; including spreads (via '...') which are arrays being spliced in; -; the other repeats (the value of) a single expression -; across one or more dimensions. -; There are two kinds of deconstructions: -; one selects a single element by index (zero-indexed); -; the other selects a range via two indices, -; the first inclusive and the second exclusive -- -; both are optional, -; the first defaulting to 0 and the second to the array length. -; Note that these expressions are all delimited -; by closing square brackets. - -array-inline-construction = "[" - array-inline-element - *( "," array-inline-element ) - "]" - -array-inline-element = expression / "..." expression - -array-repeat-construction = "[" expression ";" array-dimensions "]" - -array-construction = array-inline-construction / array-repeat-construction - -array-element-access = primary-expression "[" expression "]" - -array-range-access = primary-expression "[" [expression] ".." [expression] "]" - -array-access = array-element-access / array-range-access - -array-expression = array-construction / array-access - -; There are circuit expressions to construct and deconstruct circuit values. -; A construction lists values for all the member variables (in any order); -; there must be at least one member variable currently. -; A deconstruction selects a member variable by name. -; Note that these expressions are delimited, -; by closing curly braces or identifiers. - -circuit-construction = circuit-type "{" - circuit-inline-element *( "," circuit-inline-element ) - "}" - -circuit-inline-element = identifier ":" expression - -circuit-access = primary-expression "." identifier - -circuit-expression = circuit-construction / circuit-access - -; There are three kinds of function calls: -; top-level function calls, -; instance (i.e. non-static) member function calls, and -; static member function calls. -; What changes is the start, but they all end in an argument list, -; delimited by a closing parenthesis. - -top-level-function-call = identifier function-arguments - -instance-member-function-call = primary-expression "." - identifier function-arguments - -static-member-function-call = circuit-type "::" identifier function-arguments - -function-call = top-level-function-call - / instance-member-function-call - / static-member-function-call - -function-arguments = "(" [ expression *( "," expression ) ] ")" - -; Unary operators have the highest precedence. -; They apply to primary expressions -; and recursively to unary expressions. - -unary-expression = primary-expression - / "!" unary-expression - / "-" unary-expression - -; Next in the operator precedence is exponentiation, -; following mathematical practice. -; The current rule below makes exponentiation left-associative, -; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. -; This is easy to change if we want it to be right-associative instead. - -exponential-expression = unary-expression - / exponential-expression "**" unary-expression - -; Next in precedence come multiplication and division, both left-associative. - -multiplicative-expression = exponential-expression - / multiplicative-expression "*" exponential-expression - / multiplicative-expression "/" exponential-expression - -; Then there are addition and subtraction, both left-assocative. - -additive-expression = multiplicative-expression - / additive-expression "+" multiplicative-expression - / additive-expression "-" multiplicative-expression - -; Next in the precedence order are ordering relations. -; These are not associative, because they return boolean values. - -ordering-expression = additive-expression - / additive-expression "<" additive-expression - / additive-expression ">" additive-expression - / additive-expression "<=" additive-expression - / additive-expression ">=" additive-expression - -; Equalities return booleans but may also operate on boolean, -; so we make them left-associative. - -equality-expression = ordering-expression - / equality-expression "==" ordering-expression - / equality-expression "!=" ordering-expression - -; Next come conjunctive expressions, left-associative. - -conjunctive-expression = equality-expression - / conjunctive-expression "&&" equality-expression - -; Next come disjunctive expressions, left-associative. - -disjunctive-expression = conjunctive-expression - / disjunctive-expression "||" conjunctive-expression - -; Finally we have conditional expressions. - -conditional-expression = disjunctive-expression - / conditional-expression - "?" expression - ":" conditional-expression - -; These are all the expressions. -; Recall that conditional expressions -; may be disjunctive expressions, -; which may be conjunctive expressions, -; and so on all the way to primary expressions. - -expression = conditional-expression - -; There are various kinds of statements, -; including blocks, which are -; possibly empty sequences of statements surounded by curly braces. - -statement = expression-statement - / return-statement - / variable-definition-statement - / conditional-statement - / loop-statement - / assignment-statement - / console-statement - / block - -block = "{" *statement "}" - -; An expression (that returns the empty tuple) -; can be turned into a statement by appending a semicolon. - -expression-statement = expression ";" - -; A return statement always takes an expression, -; and does not end with a semicolon (but we may want to change that). - -return-statement = %s"return" expression - -; There are two kinds of variable definition statements, -; which only differ in the starting keyword. -; The variables are either a single one or a tuple of two or more; -; in all cases, there is just one optional type -; and just one initializing expression. - -variable-definition-statement = ( %s"let" / %s"const" ) - identifier-or-identifiers - [ ":" type ] "=" expression ";" - -identifier-or-identifiers = identifier - / "(" identifier 1*( "," identifier ) ")" - -; A conditional statement always starts with a condition and a block -; (which together form a branch). -; It may stop there, or it may continue with an alternative block, -; or possibly with another conditional statement, forming a chain. -; Note that we require blocks in all branches, not merely statements. - -branch = %s"if" expression block - -conditional-statement = branch - / branch %s"else" block - / branch %s"else" conditional-statement - -; A loop statement implicitly defines a loop variable -; that goes from a starting value (inclusive) to an ending value (exclusive). -; The body is a block. - -loop-statement = %s"for" identifier %s"in" expression ".." expression block - -; An assignment statement is straightforward. -; Based on the operator, the assignment may be simple (i.e. '=') -; or compound (i.e. combining assignment with an arithmetic operation). - -assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" - -assignment-statement = expression assignment-operator expression ";" - -; Console statements start with the 'console' keyword, -; followed by a console function call. -; The call may be an assertion or a print command. -; The former takes an expression (which must be boolean) as argument. -; The latter takes either no argument, -; or a format string followed by expressions, -; whose number must match the number of containers '{}' in the format string. -; Note that the console function names are identifiers, not keywords. -; There are three kind of printing. - -console-statement = %s"console" "." console-call - -console-call = assert-call - / print-call - -assert-call = %s"assert" "(" expression ")" - -print-function = %s"debug" / %s"error" / %s"log" - -print-arguments = "(" [ format-string *( "," expression ) ] ")" - -print-call = print-function print-arguments - -; An annotation consists of an annotation name (which starts with '@') -; with optional annotation arguments. -; Note that no parentheses are used if there are no arguments. - -annotation = annotation-name - [ "(" annotation-argument *( "," annotation-argument ) ")" ] - -; A function declaration defines a function. -; This could be called 'function-definition' instead, -; but see the comments about the 'declaration' rule below. -; The output type is optional (it defaults to the empty tuple type). -; In general, a function input consists of an identifier and a type, -; with an optional 'const' modifier. -; However, functions inside circuits -; may start with a 'mut self' or 'self' parameter, -; which may be the only parameter in fact. -; Furthermore, any function may end with an 'input' parameter, -; which may be the only parameter in fact. - -function-declaration = *annotation %s"function" identifier - "(" [ function-parameters ] ")" [ "->" type ] - block - -function-parameters = self-parameter [ "," input-parameter ] - / self-parameter "," function-inputs [ "," input-parameter ] - / function-inputs [ "," input-parameter ] - / input-parameter - -self-parameter = [%s"mut"] %s"self" - -function-inputs = function-input *( "," function-input ) - -function-input = [ %s"const" ] identifier ":" type - -input-parameter = %s"input" - -; A circuit member variable declaration consists of an identifier and a type. -; A circuit member function declaration consists of a function declaration. -; We could call these 'member-definition' etc., -; but see the comments about the 'declaration' rule below. - -member-declaration = member-variable-declaration - / member-function-declaration - -member-variable-declaration = identifier ":" type - -member-function-declaration = function-declaration - -; A circuit declaration defines a circuit type. It is straightforward. -; This could be called 'circuit-definition' instead, -; but see the comments about the 'declaration' rule below. - -circuit-declaration = *annotation %s"circuit" identifier - "{" member-declaration *( "," member-declaration ) "}" - -; An import declaration consists of the 'import' keyword -; followed by a package path, which may be one of the following: -; a single wildcard; -; an identifier, optionally followed by a local renamer; -; a package name followed by a path, recursively; -; or a parenthesized list of package paths, -; which are "fan out" of the initial path. -; Note that we allow the last element of the parenthesized list -; to be followed by a comma, presumably for convenience. - -import-declaration = %s"import" package-path - -package-path = "*" - / identifier [ %s"as" identifier ] - / package-name "." package-path - / "(" package-path *( "," package-path ) [","] ")" - -; Finally, we define a file as a sequence of zero or more declarations. -; This is why we used 'function-declaration' and 'circuit-declaration' -; instead of 'function-definition' and 'ciruit-definition': -; this way, they are all declarations of some sort. -; An import declaration cannot really called an import definition, -; because it does not define anything. -; But we may revisit this, and use 'definition' instead of 'declaration'. - -declaration = import-declaration - / function-declaration - / circuit-declaration - -file = *declaration +; Leo Library +; +; Copyright (C) 2021 Aleo Systems Inc. +; +; Author: Alessandro Coglio (acoglio on GitHub) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Format Note +; ----------- + +; The ABNF standard requires grammars to consist of lines terminated by CR LF +; (i.e. carriage return followed by line feed, DOS/Windows-style), +; as explained in the background on ABNF later in this file. +; This file's lines are therefore terminated by CR LF. +; To avoid losing this requirement across systems, +; this file is marked as 'text eol=crlf' in .gitattributes: +; this means that the file is textual, enabling visual diffs, +; but its lines will always be terminated by CR LF on any system. + +; Note that this CR LF requirement only applies to the grammar files themselves. +; It does not apply to the lines of the languages described by the grammar. +; ABNF grammar may describe any kinds of languages, +; with any kind of line terminators, +; or even without line terminators at all (e.g. for "binary" languages). + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Introduction +; ------------ + +; This file contains an initial draft of +; a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. +; Background on ABNF is provided later in this file. + +; The initial motivation for creating an ABNF grammar of Leo was that +; we have a formally verified parser of ABNF grammars +; (at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; +; also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) +; which we have used to parse this ABNF grammar of Leo +; into a formal representation, in the ACL2 theorem prover, +; of the Leo concrete syntax. +; The parsing of this grammar file into an ACL2 representation +; happens every time the ACL2 formalization of Leo is built. + +; In addition to that initial motivation, +; this ABNF grammar has now the additional and primary purpose of +; providing an official definition of the syntax of Leo +; that is both human-readable and machine-readable. +; This grammar will be part of the (upcoming) Leo language reference, +; of the Leo Language Formal Specification +; (i.e. the LaTeX document in the leo-semantics repo), +; and of the ACL2 formalization of Leo (which was the initial motivation). +; It has also been suggested that it may be used to generate tests. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Background on ABNF +; ------------------ + +; ABNF is an Internet standard: +; see https://www.rfc-editor.org/info/rfc5234 +; and https://www.rfc-editor.org/info/rfc7405. +; It is used to specify the syntax of JSON, HTTP, and other standards. + +; The following is copied (and "un-LaTeX'd") from the aforementioned paper +; (at https://www.kestrel.edu/people/coglio/vstte18.pdf). + +; ABNF adds conveniences and makes slight modifications +; to Backus-Naur Form (BNF), +; without going beyond context-free grammars. + +; Instead of BNF's angle-bracket notation for nonterminals, +; ABNF uses case-insensitive names consisting of letters, digits, and dashes, +; e.g. HTTP-message and IPv6address. +; ABNF includes an angle-bracket notation for prose descriptions, +; e.g. , +; usable as last resort in the definiens of a nonterminal. + +; While BNF allows arbitrary terminals, +; ABNF uses only natural numbers as terminals, +; and denotes them via: +; (i) binary, decimal, or hexadecimal sequences, +; e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A +; all denote the string '1 3 10'; +; (ii) binary, decimal, or hexadecimal ranges, +; e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 +; (an ASCII digit); +; (iii) case-sensitive ASCII strings, +; e.g. %s"Ab" denotes the string '65 98'; +; and (iv) case-insensitive ASCII strings, +; e.g. %i"ab", or just "ab", denotes +; any string among +; '65 66', +; '65 98', +; '97 66', and +; '97 98'. +; ABNF terminals in suitable sets represent ASCII or Unicode characters. + +; ABNF allows repetition prefixes n*m, +; where n and m are natural numbers in decimal notation; +; if absent, +; n defaults to 0, and +; m defaults to infinity. +; For example, +; 1*4HEXDIG denotes one to four HEXDIGs, +; *3DIGIT denotes up to three DIGITs, and +; 1*OCTET denotes one or more OCTETs. +; A single n prefix +; abbreviates n*n, +; e.g. 3DIGIT denotes three DIGITs. + +; Instead of BNF's |, ABNF uses / to separate alternatives. +; Repetition prefixes have precedence over juxtapositions, +; which have precedence over /. +; Round brackets group things and override the aforementioned precedence rules, +; e.g. *(WSP / CRLF WSP) denotes strings +; obtained by repeating, zero or more times, +; either (i) a WSP or (ii) a CRLF followed by a WSP. +; Square brackets also group things but make them optional, +; e.g. [":" port] is equivalent to 0*1(":" port). + +; Instead of BNF's ::=, ABNF uses = to define nonterminals, +; and =/ to incrementally add alternatives +; to previously defined nonterminals. +; For example, the rule BIT = "0" / "1" +; is equivalent to BIT = "0" followed by BIT =/ "1". + +; The syntax of ABNF itself is formally specified in ABNF +; (in Section 4 of the aforementioned RFC 5234, +; after the syntax and semantics of ABNF +; are informally specified in natural language +; (in Sections 1, 2, and 3 of the aforementioned RFC 5234). +; The syntax rules of ABNF prescribe the ASCII codes allowed for +; white space (spaces and horizontal tabs), +; line endings (carriage returns followed by line feeds), +; and comments (semicolons to line endings). + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Structure +; --------- + +; Language specifications often define the syntax of their languages via +; (i) a lexical grammar that describes how +; sequence of characters are parsed into tokens, and +; (ii) a syntactic grammar that described how +; tokens are parsed into expressions, statements, etc. +; (The adjectives 'lexical' and 'syntactic' are +; the ones used in the Java language specification; +; other terms may be used by other languages, +; but the essence is similar.) +; The situation is sometimes more complex, +; with multiple passes (e.g. Unicode escape processing in Java), +; but the division between lexical and syntactic (in the sense above) stands. + +; In the aforementioned language specifications, +; both the lexical and syntactic grammars +; are normally written in a context-free grammar notation, +; augmented with natural language that may assert, for instance, +; that tokenization always takes the longest sequence that constitutes a token. + +; This dual structure appears to be motivated by the fact that +; concerns of white space, line endings, etc. +; can be handled by the lexical grammar, +; allowing the syntactic grammar to focus on the more important structure. +; Handling both aspects in a single context-free grammar may be unwieldy, +; so having two grammars provides more clarity and readability. + +; In contrast, PEG (Parsing Expression Grammar) formalisms like Pest +; naturally embody a procedural interpretation +; that can handle white space and tokenization in just one manageable grammar. +; However, this procedural interpretaion may be sometimes +; less clear and readable to humans than context-free rules. +; Indeed, context-free grammar are commonly used to documentat languages. + +; ABNF is a context-free grammar notation, +; with no procedural interpretation, +; and therefore it makes sense to define +; separate lexical and syntactic ABNF grammars for Leo. +; Conceptually, the two grammars define two subsequent processing phases, +; as detailed below. +; However, a parser implementation does not need to perform +; two strictly separate phases (in fact, it typically does not), +; so long as it produces the same final result. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Operator Precedence +; ------------------- + +; We formulate the grammar rules for expressions +; in a way that describes the relative precedence of operators, +; as often done in language syntax specifications. + +; For instance, consider the rules +; +; multiplicative-expression = +; exponential-expression +; / multiplicative-expression "*" exponential-expression +; / multiplicative-expression "/" exponential-expression +; +; additive-expression = +; multiplicative-expression +; / additive-expression "+" multiplicative-expression +; / additive-expression "-" multiplicative-expression +; +; this rule tells us that the additive operators '+' and '-' have +; lower precedence than the multiplicative operators '*' and '/', +; and that both the additive and multiplicative operators associate to the left. +; This may be best understood via the examples given below. + +; According to the rules, the expression +; +; x + y * z +; +; can only be parsed as +; +; + +; / \ +; x * +; / \ +; y z +; +; and not as +; +; * +; / \ +; + z +; / \ +; x y +; +; because a multiplicative expression cannot have an additive expression +; as first sub-expression, as it would in the second tree above. + +; Also according to the rules, the expression +; +; x + y + z +; +; can only be parsed as +; +; + +; / \ +; + z +; / \ +; x y +; +; and not as +; +; + +; / \ +; x + +; / \ +; y z +; +; because an additive expression cannot have an additive expression +; as second sub-expression, as it would in the second tree above. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Naming Convention +; ----------------- + +; For this ABNF grammar, we choose nonterminal names +; that consist of complete English words, separated by dashes, +; and that describe the construct the way it is in English. +; For instance, we use the name 'conditional-statement' +; to describe conditional statements. + +; At the same time, we attempt to establish +; a precise and "official" nomenclature for the Leo constructs, +; by way of the nonterminal names that define their syntax. +; For instance, the rule +; +; group-literal = product-group-literal +; / affine-group-literal +; +; tells us that there are two kinds of group literals, +; namely product group literals and affine group literals. +; This is more precise than describing them as +; integers (which are not really group elements per se), +; or points (they are all points, just differently specified), +; or being singletons vs. pairs (which is a bit generic). + +; The only exception to the nomenclature-establishing role of the grammar +; is the fact that, as discussed above, +; we write the grammar rules in a way that determines +; the relative precedence and the associativity of expression operators, +; and that therefore we have rules like +; +; unary-expression = primary-expression +; / "!" unary-expression +; / "-" unary-expression +; +; In order to allow the recursion of the rule to stop, +; we need to regard, in the grammar, a primary expression as a unary expression. +; However, this is just a grammatical artifact: +; ontologically, a primary expression is not really a unary expression, +; because a unary expression is one that consists of +; a unary operator and an operand sub-expression. +; These terminological "exceptions" should be easy to identify in the rules. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Lexical Grammar +; --------------- + +; A Leo file is a finite sequence of Unicode characters, +; represented as Unicode code points, +; which are numbers in the range form 0 to 10FFFFh. +; These are captured by the ABNF rule 'character' below. + +; The lexical grammar defines how, conceptually, +; the sequence of characters is turned into +; a sequence of tokens, comments, and whitespaces. + +; As stated, the lexical grammar is ambiguous. +; For example, the sequence of characters '**' (i.e. two stars) +; could be equally parsed as two '*' symbol tokens or one '**' symbol token +; (see rule for 'symbol' below). +; As another example, the sequence or characters '' +; (i.e. carriage return followed by line feed) +; could be equally parsed as two line terminators or one +; (see rule for 'newline'). + +; Thus, as often done in language syntax definitions, +; the lexical grammar is disambiguated by +; the extra-grammatical requirement that +; the longest possible sequence of characters is always parsed. +; This way, '**' must be parsed as one '**' symbol token, +; and '' must be parsed as one line terminator. +; (We should formalize this requirement, +; along with the other extra-grammatical requirements given below, +; and formally prove that they indeed make +; the lexical grammar of Leo unambiguous.) + +; As mentioned above, a character is any Unicode code point. +; This grammar does not say how those are encoded in files (e.g. UTF-8): +; it starts with a decoded sequence of Unicode code points. +; Note that we allow any value, +; even though some values may not be used according to the Unicode standard. + +character = %x0-10FFFF ; any Unicode code point + +; We give names to certain ASCII characters. + +horizontal-tab = %x9 + +line-feed = %xA + +carriage-return = %xD + +space = %x20 + +double-quote = %x22 + +; We give names to complements of certain ASCII characters. +; These consist of all the Unicode characters except for one or two. + +not-double-quote = %x0-22 / %x24-10FFFF ; anything but " + +not-star = %x0-29 / %x2B-10FFFF ; anything but * + +not-line-feed-or-carriage-return = %x0-9 / %xB-C / %xE-10FFFF + ; anything but LF or CR + +not-star-or-slash = %x0-29 / %x2B-2E / %x30-10FFFF ; anything but * or / + +; Lines in Leo may be terminated via +; a single carriage return, +; a line feed, +; or a carriage return immediately followed by a line feed. +; Note that the latter combination constitutes a single line terminator, +; according to the extra-grammatical rule of the longest sequence. + +newline = line-feed / carriage-return / carriage-return line-feed + +; Line terminators form whitespace, along with spaces and horizontal tabs. + +whitespace = space / horizontal-tab / newline + +; There are two kinds of comments in Leo, as in other languages. +; One is block comments of the form '/* ... */', +; and the other is end-of-line comments '// ...'. +; The first kind start at '/*' and end at the first '*/', +; possibly spanning multiple (partial) lines; +; they do no nest. +; The second kind start at '//' and extend till the end of the line. +; The rules about comments given below are similar to +; the ones used in the Java language specification. + +comment = block-comment / end-of-line-comment + +block-comment = "/*" rest-of-block-comment + +rest-of-block-comment = "*" rest-of-block-comment-after-star + / not-star rest-of-block-comment + +rest-of-block-comment-after-star = "/" + / "*" rest-of-block-comment-after-star + / not-star-or-slash rest-of-block-comment + +end-of-line-comment = "//" *not-line-feed-or-carriage-return newline + +; Below are the keywords in the Leo language. +; They cannot be used as identifiers. + +keyword = %s"address" + / %s"as" + / %s"bool" + / %s"circuit" + / %s"console" + / %s"const" + / %s"else" + / %s"false" + / %s"field" + / %s"for" + / %s"function" + / %s"group" + / %s"i8" + / %s"i16" + / %s"i32" + / %s"i64" + / %s"i128" + / %s"if" + / %s"import" + / %s"in" + / %s"input" + / %s"let" + / %s"mut" + / %s"return" + / %s"Self" + / %s"self" + / %s"static" + / %s"string" + / %s"true" + / %s"u8" + / %s"u16" + / %s"u32" + / %s"u64" + / %s"u128" + +; The following rules define (ASCII) digits +; and (uppercase and lowercase) letters. + +digit = %x30-39 ; 0-9 + +uppercase-letter = %x41-5A ; A-Z + +lowercase-letter = %x61-7A ; a-z + +letter = uppercase-letter / lowercase-letter + +; An identifier is a non-empty sequence of letters, digits, and underscores, +; starting with a letter. +; It must not be a keyword: this is an extra-grammatical constraint. + +identifier = letter *( letter / digit / "_" ) ; but not a keyword + +; A package name consists of one or more segments separated by single dashes, +; where each segment is a non-empty sequence of lowercase letters and digits. + +package-name = 1*( lowercase-letter / digit ) + *( "-" 1*( lowercase-letter / digit ) ) + +; An address starts with 'aleo1' +; and continues with exactly 58 lowercase letters and digits. +; Thus an address always consists of 63 characters. + +address = %s"aleo1" 58( lowercase-letter / digit ) + +; A format string is a sequence of characters, other than double quote, +; surrounded by double quotes. +; Within a format string, substrings '{}' are distinguished as containers +; (these are the ones that may be matched with values +; whose textual representation replaces the containers +; in the printed string). +; There is an implicit extra-grammatical requirements that +; the explicit 'format-container' instances include +; all the occurrences of '{}' in the parsed character sequence: +; that is, there may not be two contiguous 'not-double-quote' instances +; that are '{' and '}'. + +format-string-container = "{}" + +format-string = double-quote + *( not-double-quote / format-string-container ) + double-quote + +; Here is (part of this ABNF comment), +; an alternative way to specify format strings, +; which captures the extra-grammatical requirement above in the grammar +; but is more complicated: +; +; not-double-quote-or-open-brace = %x0-22 / %x24-7A / %x7C-10FFFF +; +; not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF +; +; format-string-element = not-double-quote-or-open-brace +; / "{" not-double-quote-or-close-brace +; / format-container +; +; format-string = double-quote *format-string-element double-quote +; +; It is not immediately clear which approach is better; there are tradeoffs. +; Regardless, we should choose one eventually. + +; Annotations are built out of names and arguments, which are tokens. +; Two names are currently supported. +; An argument is a sequence of one or more letters, digits, and underscores. + +annotation-name = %s"@context" / %s"@test" + +annotation-argument = 1*( letter / digit / "_" ) + +; A natural (number) is a sequence of one or more digits. +; Note that we allow leading zeros, e.g. '007'. + +natural = 1*digit + +; An integer (number) is either a natural or its negation. +; Note that we also allow leading zeros in negative numbers, e.g. '-007'. + +integer = [ "-" ] natural + +; An untyped literal is just an integer. + +untyped-literal = integer + +; Unsigned literals are naturals followed by unsigned types. + +unsigned-literal = natural ( %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" ) + +; Signed literals are integers followed by signed types. + +signed-literal = integer ( %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" ) + +; Field literals are integers followed by the type of field elements. + +field-literal = integer %s"field" + +; There are two kinds of group literals. +; One is a single integer followed by the type of group elements, +; which denotes the scalar product of the generator point by the integer. +; The other is a pair of integer coordinates, +; which are reduced modulo the prime to identify a point, +; which must be on the elliptic curve. +; It is also allowed to omit one (not both) coordinates, +; with an indication of how to infer the missing coordinate +; (i.e. sign high, sign low, or inferred). + +product-group-literal = integer %s"group" + +group-coordinate = integer / "+" / "-" / "_" + +affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" + +group-literal = product-group-literal / affine-group-literal + +; Note that the rule for group literals above +; allows no whitespace between coordinates. +; If we want to allow whitespace, +; e.g. '(3, 4)group' as opposed to requiring '(3,4)group', +; then we should define affine group literals +; in the syntactic grammar instead of in the lexical grammar. +; We should have a notion of atomic literal in the lexical grammar, +; and (non-atomic) literal in the syntactic grammar. +; The lexical grammar should define a token for ')group' +; if we want no whitespace between the closing parenthesis and 'group'. +; More precisely, the rule for 'literal' below in the lexical grammar +; would be replaced with +; +; atomic-literal = ... / product-group-literal +; +; where the '...' stands for all the '...-literal' alternatives +; in the current rule for 'literal' below, except 'group-literal'. +; Furthermore, the rule for 'symbol' below in the lexical grammar +; would be extended to +; +; symbol = ... / %s")group" +; +; where '...' stands for the current definiens of the rule. +; We would also have to adjust the rule for 'token' below in the lexical grammar +; to reference 'atomic-literal' instead of 'literal' in the definiens. +; We would then add to the syntactic grammar the following rules +; +; affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" +; +; literal = atomic-literal / affine-group-literal +; +; which would now define literals in the syntactic grammar. +; Note that now an affine group literal would have the form +; +; ( , )group +; +; where is optional whitespace; +; however, no whitespace is allowed between the closing ')' and 'group'. + +; Boolean literals are the usual two. + +boolean-literal = %s"true" / %s"false" + +; An address literal is an address wrapped into an indication of address, +; to differentiate it from an identifier. + +address-literal = %s"address" "(" address ")" + +; The ones above are all the literals, as defined by the following rule. + +literal = untyped-literal + / unsigned-literal + / signed-literal + / field-literal + / group-literal + / boolean-literal + / address-literal + +; After defining the (mostly) alphanumeric tokens above, +; it remains to define tokens for non-alphanumeric symbols such as "+" and "(". +; Different programming languages used different terminologies for these, +; e.g. operators, separators, punctuators, etc. +; Here we use 'symbol', for all of them, but we can do something different. +; We could give names to all of these symbols, +; via rules such as +; +; equality-operator = "==" +; +; and defining 'symbol' in terms of those +; +; symbol = ... / equality-operator / ... +; +; This may or may not make the grammar more readable, +; but it would help establish a terminology in the grammar, +; namely the exact names of some of these token. +; On the other hand, at least some of them are perhaps simple enough +; that they could be just described in terms of their symbols, +; e.g. 'double dot', 'question mark', etc. + +symbol = "!" / "&&" / "||" + / "==" / "!=" + / "<" / "<=" / ">" / ">=" + / "+" / "-" / "*" / "/" / "**" + / "=" / "+=" / "-=" / "*=" / "/=" / "**=" + / "(" / ")" + / "[" / "]" + / "{" / "}" + / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" + / "->" + +; Everything defined above, other than comments and whitespace, +; is a token, as defined by the following rule. + +token = keyword + / identifier + / literal + / package-name + / format-string + / annotation-name + / annotation-argument + / symbol + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Syntactic Grammar +; ----------------- + +; The processing defined by the lexical grammar above +; turns the initial sequence of characters +; into a sequence of tokens, comments, and whitespaces. +; The purpose of comments and whitespaces, from a syntactic point of view, +; is just to separate tokens: +; they are discarded, leaving a sequence of tokens. +; The syntactic grammar describes how to turn +; a sequence of tokens into concrete syntax trees. + +; There are unsigned and signed integer types, for five sizes. + +unsigned-type = %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" + +signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" + +integer-type = unsigned-type / signed-type + +; The integer types, along with the field and group types, +; for the arithmetic types, i.e. the ones that support arithmetic operations. + +field-type = %s"field" + +group-type = %s"group" + +arithmetic-type = integer-type / field-type / group-type + +; The arithmetic types, along with the boolean and address types, +; form the scalar types, i.e. the ones whose values do not contain (sub)values. + +boolean-type = %s"bool" + +address-type = %s"address" + +scalar-type = boolean-type / arithmetic-type / address-type + +; Circuit types are denoted by identifiers and the keyword 'Self'. +; The latter is only allowed inside a circuit definition, +; to denote the defined circuit. + +self-type = %s"Self" + +circuit-type = identifier / self-type + +; A tuple type consists of zero, two, or more component types. + +tuple-type = "(" [ type 1*( "," type ) ] ")" + +; An array type consists of an element type +; and an indication of dimensions. +; There is either a single dimension (a number), +; or a tuple of one or more dimensions +; (we could restrict the latter to two or more dimensions). + +array-type = "[" type ";" array-dimensions "]" + +array-dimensions = natural + / "(" natural *( "," natural ) ")" + +; Circuit, tuple, and array types form the aggregate types, +; i.e. types whose values contain (sub)values +; (with the corner-case exception of the empty tuple value). + +aggregate-type = tuple-type / array-type / circuit-type + +; Scalar and aggregate types form all the types. + +type = scalar-type / aggregate-type + +; As often done in grammatical language syntax specifications, +; we define rules for different kinds of expressions, +; which also defines the relative precedence +; of operators and other expression constructs, +; and the (left or right) associativity of binary operators. + +; The primary expressions are self-contained in a way, +; i.e. they have clear deliminations. +; Some consist of single tokens: +; identifiers, the keywords 'self' and 'input', and literals. +; Primary expressions also include parenthesized expressions, +; i.e. any expression may be turned into a primary one +; by putting parentheses around it. +; The other kinds are defined and explained below. + +primary-expression = identifier + / %s"self" + / %s"input" + / literal + / "(" expression ")" + / tuple-expression + / array-expression + / circuit-expression + / function-call + +; There are tuple expressions to construct and deconstruct tuples. +; A construction consists of zero, two, or more component expressions. +; A deconstruction uses a component index (zero-indexed). +; Note that constructions are delimited by closing parentheses +; and deconstructions are delimited by natural tokens. +; The rule below, and similar rules for other aggregate types, +; use the perhaps more familiar 'access', +; but note that 'deconstruction' has a nice symmetry to 'construction'; +; the term 'destructor' has a different meaning in other languages, +; so we may want to avoid it, but not necessarily. + +tuple-construction = "(" [ expression 1*( "," expression ) ] ")" + +tuple-access = primary-expression "." natural + +tuple-expression = tuple-construction / tuple-access + +; The are array expressions to construct and deconstruct arrays. +; There are two kinds of constructions: +; one lists the element expressions (at least one), +; including spreads (via '...') which are arrays being spliced in; +; the other repeats (the value of) a single expression +; across one or more dimensions. +; There are two kinds of deconstructions: +; one selects a single element by index (zero-indexed); +; the other selects a range via two indices, +; the first inclusive and the second exclusive -- +; both are optional, +; the first defaulting to 0 and the second to the array length. +; Note that these expressions are all delimited +; by closing square brackets. + +array-inline-construction = "[" + array-inline-element + *( "," array-inline-element ) + "]" + +array-inline-element = expression / "..." expression + +array-repeat-construction = "[" expression ";" array-dimensions "]" + +array-construction = array-inline-construction / array-repeat-construction + +array-element-access = primary-expression "[" expression "]" + +array-range-access = primary-expression "[" [expression] ".." [expression] "]" + +array-access = array-element-access / array-range-access + +array-expression = array-construction / array-access + +; There are circuit expressions to construct and deconstruct circuit values. +; A construction lists values for all the member variables (in any order); +; there must be at least one member variable currently. +; A deconstruction selects a member variable by name. +; Note that these expressions are delimited, +; by closing curly braces or identifiers. + +circuit-construction = circuit-type "{" + circuit-inline-element *( "," circuit-inline-element ) + "}" + +circuit-inline-element = identifier ":" expression + +circuit-access = primary-expression "." identifier + +circuit-expression = circuit-construction / circuit-access + +; There are three kinds of function calls: +; top-level function calls, +; instance (i.e. non-static) member function calls, and +; static member function calls. +; What changes is the start, but they all end in an argument list, +; delimited by a closing parenthesis. + +top-level-function-call = identifier function-arguments + +instance-member-function-call = primary-expression "." + identifier function-arguments + +static-member-function-call = circuit-type "::" identifier function-arguments + +function-call = top-level-function-call + / instance-member-function-call + / static-member-function-call + +function-arguments = "(" [ expression *( "," expression ) ] ")" + +; Unary operators have the highest precedence. +; They apply to primary expressions +; and recursively to unary expressions. + +unary-expression = primary-expression + / "!" unary-expression + / "-" unary-expression + +; Next in the operator precedence is exponentiation, +; following mathematical practice. +; The current rule below makes exponentiation left-associative, +; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. +; This is easy to change if we want it to be right-associative instead. + +exponential-expression = unary-expression + / exponential-expression "**" unary-expression + +; Next in precedence come multiplication and division, both left-associative. + +multiplicative-expression = exponential-expression + / multiplicative-expression "*" exponential-expression + / multiplicative-expression "/" exponential-expression + +; Then there are addition and subtraction, both left-assocative. + +additive-expression = multiplicative-expression + / additive-expression "+" multiplicative-expression + / additive-expression "-" multiplicative-expression + +; Next in the precedence order are ordering relations. +; These are not associative, because they return boolean values. + +ordering-expression = additive-expression + / additive-expression "<" additive-expression + / additive-expression ">" additive-expression + / additive-expression "<=" additive-expression + / additive-expression ">=" additive-expression + +; Equalities return booleans but may also operate on boolean, +; so we make them left-associative. + +equality-expression = ordering-expression + / equality-expression "==" ordering-expression + / equality-expression "!=" ordering-expression + +; Next come conjunctive expressions, left-associative. + +conjunctive-expression = equality-expression + / conjunctive-expression "&&" equality-expression + +; Next come disjunctive expressions, left-associative. + +disjunctive-expression = conjunctive-expression + / disjunctive-expression "||" conjunctive-expression + +; Finally we have conditional expressions. + +conditional-expression = disjunctive-expression + / conditional-expression + "?" expression + ":" conditional-expression + +; These are all the expressions. +; Recall that conditional expressions +; may be disjunctive expressions, +; which may be conjunctive expressions, +; and so on all the way to primary expressions. + +expression = conditional-expression + +; There are various kinds of statements, +; including blocks, which are +; possibly empty sequences of statements surounded by curly braces. + +statement = expression-statement + / return-statement + / variable-definition-statement + / conditional-statement + / loop-statement + / assignment-statement + / console-statement + / block + +block = "{" *statement "}" + +; An expression (that returns the empty tuple) +; can be turned into a statement by appending a semicolon. + +expression-statement = expression ";" + +; A return statement always takes an expression, +; and does not end with a semicolon (but we may want to change that). + +return-statement = %s"return" expression + +; There are two kinds of variable definition statements, +; which only differ in the starting keyword. +; The variables are either a single one or a tuple of two or more; +; in all cases, there is just one optional type +; and just one initializing expression. + +variable-definition-statement = ( %s"let" / %s"const" ) + identifier-or-identifiers + [ ":" type ] "=" expression ";" + +identifier-or-identifiers = identifier + / "(" identifier 1*( "," identifier ) ")" + +; A conditional statement always starts with a condition and a block +; (which together form a branch). +; It may stop there, or it may continue with an alternative block, +; or possibly with another conditional statement, forming a chain. +; Note that we require blocks in all branches, not merely statements. + +branch = %s"if" expression block + +conditional-statement = branch + / branch %s"else" block + / branch %s"else" conditional-statement + +; A loop statement implicitly defines a loop variable +; that goes from a starting value (inclusive) to an ending value (exclusive). +; The body is a block. + +loop-statement = %s"for" identifier %s"in" expression ".." expression block + +; An assignment statement is straightforward. +; Based on the operator, the assignment may be simple (i.e. '=') +; or compound (i.e. combining assignment with an arithmetic operation). + +assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" + +assignment-statement = expression assignment-operator expression ";" + +; Console statements start with the 'console' keyword, +; followed by a console function call. +; The call may be an assertion or a print command. +; The former takes an expression (which must be boolean) as argument. +; The latter takes either no argument, +; or a format string followed by expressions, +; whose number must match the number of containers '{}' in the format string. +; Note that the console function names are identifiers, not keywords. +; There are three kind of printing. + +console-statement = %s"console" "." console-call + +console-call = assert-call + / print-call + +assert-call = %s"assert" "(" expression ")" + +print-function = %s"debug" / %s"error" / %s"log" + +print-arguments = "(" [ format-string *( "," expression ) ] ")" + +print-call = print-function print-arguments + +; An annotation consists of an annotation name (which starts with '@') +; with optional annotation arguments. +; Note that no parentheses are used if there are no arguments. + +annotation = annotation-name + [ "(" annotation-argument *( "," annotation-argument ) ")" ] + +; A function declaration defines a function. +; This could be called 'function-definition' instead, +; but see the comments about the 'declaration' rule below. +; The output type is optional (it defaults to the empty tuple type). +; In general, a function input consists of an identifier and a type, +; with an optional 'const' modifier. +; However, functions inside circuits +; may start with a 'mut self' or 'self' parameter, +; which may be the only parameter in fact. +; Furthermore, any function may end with an 'input' parameter, +; which may be the only parameter in fact. + +function-declaration = *annotation %s"function" identifier + "(" [ function-parameters ] ")" [ "->" type ] + block + +function-parameters = self-parameter [ "," input-parameter ] + / self-parameter "," function-inputs [ "," input-parameter ] + / function-inputs [ "," input-parameter ] + / input-parameter + +self-parameter = [%s"mut"] %s"self" + +function-inputs = function-input *( "," function-input ) + +function-input = [ %s"const" ] identifier ":" type + +input-parameter = %s"input" + +; A circuit member variable declaration consists of an identifier and a type. +; A circuit member function declaration consists of a function declaration. +; We could call these 'member-definition' etc., +; but see the comments about the 'declaration' rule below. + +member-declaration = member-variable-declaration + / member-function-declaration + +member-variable-declaration = identifier ":" type + +member-function-declaration = function-declaration + +; A circuit declaration defines a circuit type. It is straightforward. +; This could be called 'circuit-definition' instead, +; but see the comments about the 'declaration' rule below. + +circuit-declaration = *annotation %s"circuit" identifier + "{" member-declaration *( "," member-declaration ) "}" + +; An import declaration consists of the 'import' keyword +; followed by a package path, which may be one of the following: +; a single wildcard; +; an identifier, optionally followed by a local renamer; +; a package name followed by a path, recursively; +; or a parenthesized list of package paths, +; which are "fan out" of the initial path. +; Note that we allow the last element of the parenthesized list +; to be followed by a comma, presumably for convenience. + +import-declaration = %s"import" package-path + +package-path = "*" + / identifier [ %s"as" identifier ] + / package-name "." package-path + / "(" package-path *( "," package-path ) [","] ")" + +; Finally, we define a file as a sequence of zero or more declarations. +; This is why we used 'function-declaration' and 'circuit-declaration' +; instead of 'function-definition' and 'ciruit-definition': +; this way, they are all declarations of some sort. +; An import declaration cannot really called an import definition, +; because it does not define anything. +; But we may revisit this, and use 'definition' instead of 'declaration'. + +declaration = import-declaration + / function-declaration + / circuit-declaration + +file = *declaration diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index 8236e85362..9cf47c2200 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -323,6 +323,7 @@ impl Token { "as" => Token::As, "bool" => Token::Bool, "circuit" => Token::Circuit, + "console" => Token::Console, "const" => Token::Const, "else" => Token::Else, "false" => Token::False, @@ -330,11 +331,11 @@ impl Token { "for" => Token::For, "function" => Token::Function, "group" => Token::Group, - "i128" => Token::I128, - "i64" => Token::I64, - "i32" => Token::I32, - "i16" => Token::I16, "i8" => Token::I8, + "i16" => Token::I16, + "i32" => Token::I32, + "i64" => Token::I64, + "i128" => Token::I128, "if" => Token::If, "import" => Token::Import, "in" => Token::In, @@ -342,17 +343,16 @@ impl Token { "let" => Token::Let, "mut" => Token::Mut, "return" => Token::Return, - "static" => Token::Static, - "string" => Token::Str, - "true" => Token::True, - "u128" => Token::U128, - "u64" => Token::U64, - "u32" => Token::U32, - "u16" => Token::U16, - "u8" => Token::U8, "Self" => Token::BigSelf, "self" => Token::LittleSelf, - "console" => Token::Console, + "static" => Token::Static, + "string" => Token::String, + "true" => Token::True, + "u8" => Token::U8, + "u16" => Token::U16, + "u32" => Token::U32, + "u64" => Token::U64, + "u128" => Token::U128, _ => Token::Ident(ident), }), ); diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index 18604d64db..1bcad98c28 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -36,12 +36,13 @@ impl fmt::Display for FormattedStringPart { /// Represents all valid Leo syntax tokens. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Token { + CommentLine(String), + CommentBlock(String), + FormattedString(Vec), AddressLit(String), Ident(String), Int(String), - CommentLine(String), - CommentBlock(String), Not, NotEq, And, @@ -98,7 +99,7 @@ pub enum Token { Mut, Return, Static, - Str, + String, True, U128, U64, @@ -137,6 +138,7 @@ pub const KEYWORD_TOKENS: &[Token] = &[ Token::As, Token::Bool, Token::Circuit, + Token::Console, Token::Const, Token::Else, Token::False, @@ -144,11 +146,11 @@ pub const KEYWORD_TOKENS: &[Token] = &[ Token::For, Token::Function, Token::Group, - Token::I128, - Token::I64, - Token::I32, - Token::I16, Token::I8, + Token::I16, + Token::I32, + Token::I64, + Token::I128, Token::If, Token::Import, Token::In, @@ -156,17 +158,16 @@ pub const KEYWORD_TOKENS: &[Token] = &[ Token::Let, Token::Mut, Token::Return, - Token::Static, - Token::Str, - Token::True, - Token::U128, - Token::U64, - Token::U32, - Token::U16, - Token::U8, Token::BigSelf, Token::LittleSelf, - Token::Console, + Token::Static, + Token::String, + Token::True, + Token::U8, + Token::U16, + Token::U32, + Token::U64, + Token::U128, ]; impl Token { @@ -251,7 +252,7 @@ impl fmt::Display for Token { Mut => write!(f, "mut"), Return => write!(f, "return"), Static => write!(f, "static"), - Str => write!(f, "string"), + String => write!(f, "string"), True => write!(f, "true"), U128 => write!(f, "u128"), U64 => write!(f, "u64"), From 0663227741b8ecdef8169167102d6f4bb9ce8351 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 13:45:57 -0400 Subject: [PATCH 006/108] order tokens to try and match ABNF --- grammar/abnf-grammar.txt | 15 +++-- parser/src/tokenizer/token.rs | 113 +++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 54 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 98ab3d56a6..d6d4b6902a 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -476,14 +476,14 @@ address = %s"aleo1" 58( lowercase-letter / digit ) ; whose textual representation replaces the containers ; in the printed string). ; There is an implicit extra-grammatical requirements that -; the explicit 'format-container' instances include +; the explicit 'format-string-container' instances include ; all the occurrences of '{}' in the parsed character sequence: ; that is, there may not be two contiguous 'not-double-quote' instances ; that are '{' and '}'. format-string-container = "{}" -format-string = double-quote +formatted-string = double-quote *( not-double-quote / format-string-container ) double-quote @@ -498,9 +498,9 @@ format-string = double-quote ; ; format-string-element = not-double-quote-or-open-brace ; / "{" not-double-quote-or-close-brace -; / format-container +; / format-string-container ; -; format-string = double-quote *format-string-element double-quote +; formatted-string = double-quote *format-string-element double-quote ; ; It is not immediately clear which approach is better; there are tradeoffs. ; Regardless, we should choose one eventually. @@ -811,6 +811,11 @@ array-expression = array-construction / array-access ; There are circuit expressions to construct and deconstruct circuit values. ; A construction lists values for all the member variables (in any order); ; there must be at least one member variable currently. +; A single identifier abbreviates +; a pair consisting of the same identifier separated by dot; +; note that, in the expansion, the left one denotes a member name, +; while the right one denotes an expression (a variable), +; so they are syntactically identical but semantically different. ; A deconstruction selects a member variable by name. ; Note that these expressions are delimited, ; by closing curly braces or identifiers. @@ -819,7 +824,7 @@ circuit-construction = circuit-type "{" circuit-inline-element *( "," circuit-inline-element ) "}" -circuit-inline-element = identifier ":" expression +circuit-inline-element = identifier ":" expression / identifier circuit-access = primary-expression "." identifier diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index 1bcad98c28..43e6250bc7 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -36,82 +36,98 @@ impl fmt::Display for FormattedStringPart { /// Represents all valid Leo syntax tokens. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Token { + // Lexical Grammar + // Literals CommentLine(String), CommentBlock(String), - FormattedString(Vec), - AddressLit(String), Ident(String), Int(String), + True, + False, + AddressLit(String), + + At, + + // Symbols Not, - NotEq, And, + Or, + Eq, + NotEq, + Lt, + LtEq, + Gt, + GtEq, + Add, + Minus, + Mul, + Div, + Exp, + Assign, + AddEq, + MinusEq, + MulEq, + DivEq, + ExpEq, LeftParen, RightParen, - Mul, - Exp, - ExpEq, - MulEq, - Add, - AddEq, + LeftSquare, + RightSquare, + LeftCurly, + RightCurly, Comma, - Minus, - MinusEq, - Arrow, Dot, DotDot, DotDotDot, - Div, - DivEq, + Semicolon, Colon, DoubleColon, - Semicolon, - Lt, - LtEq, - Assign, - Eq, - Gt, - GtEq, - At, - LeftSquare, - RightSquare, - Address, - As, + Question, + Arrow, + + // Syntactic Grammr + // Types + U8, + U16, + U32, + U64, + U128, + I8, + I16, + I32, + I64, + I128, + Field, + Group, Bool, + Address, + BigSelf, + + // primary expresion + Input, + LittleSelf, + + // Import + Import, + + // Regular Keywords + As, Circuit, + Console, Const, Else, - False, - Field, For, Function, - Group, - I128, - I64, - I32, - I16, - I8, If, - Import, In, - Input, Let, Mut, Return, Static, String, - True, - U128, - U64, - U32, - U16, - U8, - BigSelf, - LittleSelf, - Console, - LeftCurly, - RightCurly, - Or, + + // Not yet in ABNF BitAnd, BitAndEq, BitOr, @@ -129,7 +145,6 @@ pub enum Token { ModEq, OrEq, AndEq, - Question, } /// Represents all valid Leo keyword tokens. From 8c996fb15d898eb218cad818032dced84e31e217 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 16:02:01 -0400 Subject: [PATCH 007/108] do not allow _ at start of identifier --- parser/src/parser/context.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index 1c3f41f53e..38fedc74a8 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -302,6 +302,10 @@ impl ParserContext { span, } = token { + if name.starts_with('_') { + return Err(SyntaxError::invalid_ident_name(&name, &name[1..name.len()], &span)); + } + Ok(Identifier { name, span }) } else { unimplemented!() From 62e68f42daaf897a92880119e157258cb9130a22 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 16:06:39 -0400 Subject: [PATCH 008/108] forgot to push new error with previous commit --- parser/src/errors/syntax.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index c453625d94..93f52eaefc 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -72,6 +72,10 @@ impl SyntaxError { ) } + pub fn invalid_ident_name(got: &str, expected: &str, span: &Span) -> Self { + Self::new_from_span(format!("expected identifier {} -- got '{}'", expected, got), span) + } + pub fn unexpected_ident(got: &str, expected: &[&str], span: &Span) -> Self { Self::new_from_span( format!( From 026816f0852beba699f8ced9ae88f4526429fe0a Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 16:45:43 -0400 Subject: [PATCH 009/108] cleaner way to remove _ from beginning of idents --- parser/src/errors/syntax.rs | 4 ---- parser/src/parser/context.rs | 6 +++--- parser/src/tokenizer/lexer.rs | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index 93f52eaefc..c453625d94 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -72,10 +72,6 @@ impl SyntaxError { ) } - pub fn invalid_ident_name(got: &str, expected: &str, span: &Span) -> Self { - Self::new_from_span(format!("expected identifier {} -- got '{}'", expected, got), span) - } - pub fn unexpected_ident(got: &str, expected: &[&str], span: &Span) -> Self { Self::new_from_span( format!( diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index 38fedc74a8..1b995b7335 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -302,9 +302,9 @@ impl ParserContext { span, } = token { - if name.starts_with('_') { - return Err(SyntaxError::invalid_ident_name(&name, &name[1..name.len()], &span)); - } + // if name.starts_with('_') { + // return Err(SyntaxError::invalid_ident_name(&name, &name[1..name.len()], &span)); + // } Ok(Identifier { name, span }) } else { diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index 9cf47c2200..daf12b1e8b 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -43,7 +43,7 @@ fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { if input.is_empty() { return None; } - if !input[0].is_ascii_alphabetic() && input[0] != b'_' { + if !input[0].is_ascii_alphabetic() { return None; } let mut i = 1usize; From 98fd0ac4dc7cd9f44873988f4d2ff973a30a0049 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 17:27:45 -0400 Subject: [PATCH 010/108] rename function names to reflect abnf more --- parser/src/parser/expression.rs | 61 +++++++++++++++++---------------- parser/src/parser/file.rs | 18 +++++----- parser/src/parser/statement.rs | 4 +-- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index f8dbac1f0e..bb6b546324 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -56,11 +56,11 @@ 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_or_expression`]. + /// Otherwise, tries to parse the next token using [`parse_disjunctive_expression`]. /// pub fn parse_expression_fuzzy(&mut self) -> SyntaxResult { // Try to parse the next expression. Try BinaryOperation::Or. - let mut expr = self.parse_or_expression()?; + let mut expr = self.parse_disjunctive_expression()?; // Parse the rest of the ternary expression. if self.eat(Token::Question).is_some() { @@ -81,12 +81,12 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent /// a binary or expression. /// - /// Otherwise, tries to parse the next token using [`parse_and_expression`]. + /// Otherwise, tries to parse the next token using [`parse_conjunctive_expression`]. /// - pub fn parse_or_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_and_expression()?; + pub fn parse_disjunctive_expression(&mut self) -> SyntaxResult { + let mut expr = self.parse_conjunctive_expression()?; while self.eat(Token::Or).is_some() { - let right = self.parse_and_expression()?; + let right = self.parse_conjunctive_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: BinaryOperation::Or, @@ -103,7 +103,7 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_bit_or_expression`]. /// - pub fn parse_and_expression(&mut self) -> SyntaxResult { + pub fn parse_conjunctive_expression(&mut self) -> SyntaxResult { let mut expr = self.parse_bit_or_expression()?; while self.eat(Token::And).is_some() { let right = self.parse_bit_or_expression()?; @@ -161,12 +161,12 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent a /// binary bitwise and expression. /// - /// Otherwise, tries to parse the next token using [`parse_eq_expression`]. + /// Otherwise, tries to parse the next token using [`parse_equality_expression`]. /// pub fn parse_bit_and_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_eq_expression()?; + let mut expr = self.parse_equality_expression()?; while self.eat(Token::BitAnd).is_some() { - let right = self.parse_eq_expression()?; + let right = self.parse_equality_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: BinaryOperation::BitAnd, @@ -181,12 +181,12 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent a /// binary equals or not equals expression. /// - /// Otherwise, tries to parse the next token using [`parse_rel_expression`]. + /// Otherwise, tries to parse the next token using [`parse_ordering_expression`]. /// - pub fn parse_eq_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_rel_expression()?; + pub fn parse_equality_expression(&mut self) -> SyntaxResult { + let mut expr = self.parse_ordering_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Eq, Token::NotEq]) { - let right = self.parse_rel_expression()?; + let right = self.parse_ordering_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { @@ -207,7 +207,7 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_shift_expression`]. /// - pub fn parse_rel_expression(&mut self) -> SyntaxResult { + pub fn parse_ordering_expression(&mut self) -> SyntaxResult { let mut expr = self.parse_shift_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) { @@ -232,12 +232,12 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent a /// binary shift expression. /// - /// Otherwise, tries to parse the next token using [`parse_add_sub_expression`]. + /// Otherwise, tries to parse the next token using [`parse_additive_expression`]. /// pub fn parse_shift_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_add_sub_expression()?; + let mut expr = self.parse_additive_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Shl, Token::Shr, Token::ShrSigned]) { - let right = self.parse_add_sub_expression()?; + let right = self.parse_additive_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { @@ -259,10 +259,10 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_mul_div_pow_expression`]. /// - pub fn parse_add_sub_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_mul_div_mod_expression()?; + pub fn parse_additive_expression(&mut self) -> SyntaxResult { + let mut expr = self.parse_multiplicative_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Add, Token::Minus]) { - let right = self.parse_mul_div_mod_expression()?; + let right = self.parse_multiplicative_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { @@ -281,12 +281,12 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent a /// binary multiplication, division, or modulus expression. /// - /// Otherwise, tries to parse the next token using [`parse_exp_expression`]. + /// Otherwise, tries to parse the next token using [`parse_exponential_expression`]. /// - pub fn parse_mul_div_mod_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_exp_expression()?; + pub fn parse_multiplicative_expression(&mut self) -> SyntaxResult { + let mut expr = self.parse_exponential_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Mul, Token::Div, Token::Mod]) { - let right = self.parse_exp_expression()?; + let right = self.parse_exponential_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { @@ -308,7 +308,7 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_cast_expression`]. /// - pub fn parse_exp_expression(&mut self) -> SyntaxResult { + pub fn parse_exponential_expression(&mut self) -> SyntaxResult { let mut exprs = vec![]; exprs.push(self.parse_cast_expression()?); while self.eat(Token::Exp).is_some() { @@ -507,7 +507,7 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent an /// circuit initialization expression. /// - pub fn parse_circuit_init(&mut self, identifier: Identifier) -> SyntaxResult { + pub fn parse_circuit_expression(&mut self, identifier: Identifier) -> SyntaxResult { self.expect(Token::LeftCurly)?; let mut members = vec![]; let end_span; @@ -543,9 +543,10 @@ impl ParserContext { /// /// Returns an [`Expression`] AST node if the next token is a primary expression: - /// - Scalar types: field, group, unsigned integer, signed integer, boolean, address + /// - Literals: field, group, unsigned integer, signed integer, boolean, address /// - Aggregate types: array, tuple /// - Identifiers: variables, keywords + /// - self /// /// Returns an expression error if the token cannot be matched. /// @@ -676,7 +677,7 @@ impl ParserContext { Token::Ident(name) => { let ident = Identifier { name, span }; if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly { - self.parse_circuit_init(ident)? + self.parse_circuit_expression(ident)? } else { Expression::Identifier(ident) } @@ -687,7 +688,7 @@ impl ParserContext { span, }; if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly { - self.parse_circuit_init(ident)? + self.parse_circuit_expression(ident)? } else { Expression::Identifier(ident) } diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index f61f228976..c873c0cdbe 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -39,7 +39,7 @@ impl ParserContext { circuits.insert(id, circuit); } Token::Function | Token::At => { - let (id, function) = self.parse_function()?; + let (id, function) = self.parse_function_declaration()?; functions.insert(id, function); } Token::Ident(ident) if ident == "test" => { @@ -47,7 +47,7 @@ impl ParserContext { &token.span, ))); // self.expect(Token::Test)?; - // let (id, function) = self.parse_function()?; + // let (id, function) = self.parse_function_declaration()?; // tests.insert(id, TestFunction { // function, // input_file: None, @@ -153,7 +153,7 @@ impl ParserContext { token: Token::Ident(name.name), span: name.span, }); - Ok(match self.parse_package_or_packages()? { + Ok(match self.parse_package_path()? { PackageOrPackages::Package(p) => PackageAccess::SubPackage(Box::new(p)), PackageOrPackages::Packages(p) => PackageAccess::Multiple(p), }) @@ -233,7 +233,7 @@ impl ParserContext { /// Returns a [`PackageOrPackages`] AST node if the next tokens represent a valid package import /// with accesses. /// - pub fn parse_package_or_packages(&mut self) -> SyntaxResult { + pub fn parse_package_path(&mut self) -> SyntaxResult { let package_name = self.parse_package_name()?; self.expect(Token::Dot)?; if self.peek()?.token == Token::LeftParen { @@ -258,7 +258,7 @@ impl ParserContext { /// pub fn parse_import(&mut self) -> SyntaxResult { self.expect(Token::Import)?; - let package_or_packages = self.parse_package_or_packages()?; + let package_or_packages = self.parse_package_path()?; self.expect(Token::Semicolon)?; Ok(ImportStatement { span: package_or_packages.span().clone(), @@ -273,7 +273,7 @@ impl ParserContext { pub fn parse_circuit_member(&mut self) -> SyntaxResult { let peeked = &self.peek()?.token; if peeked == &Token::Function || peeked == &Token::At { - let function = self.parse_function()?; + let function = self.parse_function_declaration()?; Ok(CircuitMember::CircuitFunction(function.1)) } else { // circuit variable @@ -307,7 +307,7 @@ impl ParserContext { /// /// Returns a [`FunctionInput`] AST node if the next tokens represent a function parameter. /// - pub fn parse_function_input(&mut self) -> SyntaxResult { + pub fn parse_function_parameters(&mut self) -> SyntaxResult { if let Some(token) = self.eat(Token::Input) { return Ok(FunctionInput::InputKeyword(InputKeyword { identifier: Identifier { @@ -352,7 +352,7 @@ impl ParserContext { /// Returns an [`(Identifier, Function)`] AST node if the next tokens represent a function name /// and function definition. /// - pub fn parse_function(&mut self) -> SyntaxResult<(Identifier, Function)> { + pub fn parse_function_declaration(&mut self) -> SyntaxResult<(Identifier, Function)> { let mut annotations = vec![]; while self.peek()?.token == Token::At { annotations.push(self.parse_annotation()?); @@ -362,7 +362,7 @@ impl ParserContext { self.expect(Token::LeftParen)?; let mut inputs = vec![]; while self.eat(Token::RightParen).is_none() { - let input = self.parse_function_input()?; + let input = self.parse_function_parameters()?; inputs.push(input); if self.eat(Token::Comma).is_none() { self.expect(Token::RightParen)?; diff --git a/parser/src/parser/statement.rs b/parser/src/parser/statement.rs index c01190fa0b..549c119fc6 100644 --- a/parser/src/parser/statement.rs +++ b/parser/src/parser/statement.rs @@ -89,7 +89,7 @@ impl ParserContext { match &self.peek()?.token { Token::Return => Ok(Statement::Return(self.parse_return_statement()?)), Token::If => Ok(Statement::Conditional(self.parse_conditional_statement()?)), - Token::For => Ok(Statement::Iteration(self.parse_for_statement()?)), + Token::For => Ok(Statement::Iteration(self.parse_loop_statement()?)), Token::Console => Ok(Statement::Console(self.parse_console_statement()?)), Token::Let | Token::Const => Ok(Statement::Definition(self.parse_definition_statement()?)), Token::LeftCurly => Ok(Statement::Block(self.parse_block()?)), @@ -195,7 +195,7 @@ impl ParserContext { /// /// Returns an [`IterationStatement`] AST node if the next tokens represent an iteration statement. /// - pub fn parse_for_statement(&mut self) -> SyntaxResult { + pub fn parse_loop_statement(&mut self) -> SyntaxResult { let start_span = self.expect(Token::For)?; let ident = self.expect_ident()?; self.expect(Token::In)?; From becafb379855d317e6724c537a5cde2b053c83ab Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 17:35:55 -0400 Subject: [PATCH 011/108] fix some cases where _ is the only character in the identifier --- parser/src/tokenizer/lexer.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index daf12b1e8b..b81d306628 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -43,7 +43,12 @@ fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { if input.is_empty() { return None; } - if !input[0].is_ascii_alphabetic() { + if !input[0].is_ascii_alphabetic() && input[0] != b'_' { + // Allow _ at start. + return None; + } + if input.len() > 1 && input[0] == b'_' { + // But only if it the length of the identifer is 1. return None; } let mut i = 1usize; From c9daf4a8a9a63e596f80c125394dc140faf8281c Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 23 Mar 2021 17:42:54 -0400 Subject: [PATCH 012/108] typed one thing in the comment and another in the if condition whoops --- parser/src/tokenizer/lexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index b81d306628..d079a807a8 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -47,7 +47,7 @@ fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { // Allow _ at start. return None; } - if input.len() > 1 && input[0] == b'_' { + if input.len() == 1 && input[0] == b'_' { // But only if it the length of the identifer is 1. return None; } From fd52192d58459e2478408b6a96a93f6ed1b77f3a Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 11:40:26 -0400 Subject: [PATCH 013/108] _ token in parser and symbol in abnf --- grammar/abnf-grammar.txt | 2 +- parser/src/parser/context.rs | 2 +- parser/src/tokenizer/lexer.rs | 8 +++----- parser/src/tokenizer/mod.rs | 3 ++- parser/src/tokenizer/token.rs | 2 ++ 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index d6d4b6902a..668e8134dc 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -645,7 +645,7 @@ symbol = "!" / "&&" / "||" / "[" / "]" / "{" / "}" / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" - / "->" + / "->" / "_" ; Everything defined above, other than comments and whitespace, ; is a token, as defined by the following rule. diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index 1b995b7335..a43bb783ed 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -153,7 +153,7 @@ impl ParserContext { } _ => GroupCoordinate::SignLow, }, - Token::Ident(x) if x == "_" => GroupCoordinate::Inferred, + Token::Underscore => GroupCoordinate::Inferred, Token::Int(value) => GroupCoordinate::Number(value.clone(), token.span.clone()), _ => return None, }) diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index d079a807a8..d3b04e54d9 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -43,14 +43,11 @@ fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { if input.is_empty() { return None; } - if !input[0].is_ascii_alphabetic() && input[0] != b'_' { + if !input[0].is_ascii_alphabetic() { // Allow _ at start. return None; } - if input.len() == 1 && input[0] == b'_' { - // But only if it the length of the identifer is 1. - return None; - } + let mut i = 1usize; while i < input.len() { if !input[i].is_ascii_alphanumeric() && input[i] != b'_' { @@ -283,6 +280,7 @@ impl Token { } return (&input[1..], Some(Token::Assign)); } + b'_' => return (&input[1..], Some(Token::Underscore)), b'@' => return (&input[1..], Some(Token::At)), b'[' => return (&input[1..], Some(Token::LeftSquare)), b']' => return (&input[1..], Some(Token::RightSquare)), diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 7cfe52175f..1d4848f7d4 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -172,6 +172,7 @@ mod tests { - -= -> + _ . .. ... @@ -221,7 +222,7 @@ mod tests { } assert_eq!( output, - r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= ? // test + r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= ? // test /* test */ // "# ); diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index 43e6250bc7..3af070fe26 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -85,6 +85,7 @@ pub enum Token { DoubleColon, Question, Arrow, + Underscore, // Syntactic Grammr // Types @@ -298,6 +299,7 @@ impl fmt::Display for Token { OrEq => write!(f, "||="), AndEq => write!(f, "&&="), Question => write!(f, "?"), + Underscore => write!(f, "_"), } } } From 600cf120f9c8a06f881f1421e4c6c89d44e8156a Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 12:08:07 -0400 Subject: [PATCH 014/108] idents in annotation name and for arguements, no white space between @ and annotation-name --- grammar/abnf-grammar.txt | 7 ++----- parser/src/errors/syntax.rs | 7 +++++++ parser/src/parser/file.rs | 8 ++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 668e8134dc..fc5606fbb1 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -509,9 +509,7 @@ formatted-string = double-quote ; Two names are currently supported. ; An argument is a sequence of one or more letters, digits, and underscores. -annotation-name = %s"@context" / %s"@test" - -annotation-argument = 1*( letter / digit / "_" ) +annotation-name = "@" identifier ; A natural (number) is a sequence of one or more digits. ; Note that we allow leading zeros, e.g. '007'. @@ -656,7 +654,6 @@ token = keyword / package-name / format-string / annotation-name - / annotation-argument / symbol ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1012,7 +1009,7 @@ print-call = print-function print-arguments ; Note that no parentheses are used if there are no arguments. annotation = annotation-name - [ "(" annotation-argument *( "," annotation-argument ) ")" ] + [ "(" identifier *( "," identifier ) ")" ] ; A function declaration defines a function. ; This could be called 'function-definition' instead, diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index c453625d94..3c7efab8a0 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -57,6 +57,13 @@ impl SyntaxError { Self::new_from_span("unexpected EOF".to_string(), span) } + pub fn unexpected_whitespace(left: &str, right: &str, span: &Span) -> Self { + Self::new_from_span( + format!("Unexpected white space between terms {} and {}", left, right), + span, + ) + } + pub fn unexpected(got: &Token, expected: &[Token], span: &Span) -> Self { Self::new_from_span( format!( diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index c873c0cdbe..175121376d 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -88,6 +88,14 @@ impl ParserContext { &name.span, ))); } + + if start.col_stop != name.span.col_start { + let mut error_span = &start + &name.span; + error_span.col_start = start.col_stop - 1; + error_span.col_stop = name.span.col_start - 1; + return Err(SyntaxError::unexpected_whitespace("@", &name.name, &error_span)); + } + let end_span; let arguments = if self.eat(Token::LeftParen).is_some() { let mut args = vec![]; From e0200ff78912379417dc93dc75a4c4c2c3044640 Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 12:33:52 -0400 Subject: [PATCH 015/108] tentative cast-expression abnf rule, refactor fuzzy rule to conditional expression --- grammar/abnf-grammar.txt | 8 ++++++-- parser/src/parser/expression.rs | 6 +++--- parser/src/parser/statement.rs | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index fc5606fbb1..72d970994d 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -902,12 +902,16 @@ conjunctive-expression = equality-expression disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression -; Finally we have conditional expressions. +; Next come conditional expressions. conditional-expression = disjunctive-expression - / conditional-expression + / conditional-expression "?" expression ":" conditional-expression + +; Need to decide on operator precedence for as. +cast-expression = conditional-expression + / cast-expression %s"as" type ; These are all the expressions. ; Recall that conditional expressions diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index bb6b546324..db4ce05f21 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -44,7 +44,7 @@ impl ParserContext { self.fuzzy_struct_state = false; // Parse expression. - let result = self.parse_expression_fuzzy(); + let result = self.parse_conditional_expression(); // Restore prior parser state. self.fuzzy_struct_state = prior_fuzzy_state; @@ -58,7 +58,7 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_disjunctive_expression`]. /// - pub fn parse_expression_fuzzy(&mut self) -> SyntaxResult { + pub fn parse_conditional_expression(&mut self) -> SyntaxResult { // Try to parse the next expression. Try BinaryOperation::Or. let mut expr = self.parse_disjunctive_expression()?; @@ -66,7 +66,7 @@ impl ParserContext { if self.eat(Token::Question).is_some() { let if_true = self.parse_expression()?; self.expect(Token::Colon)?; - let if_false = self.parse_expression_fuzzy()?; + let if_false = self.parse_conditional_expression()?; expr = Expression::Ternary(TernaryExpression { span: expr.span() + if_false.span(), condition: Box::new(expr), diff --git a/parser/src/parser/statement.rs b/parser/src/parser/statement.rs index 549c119fc6..8ca277e591 100644 --- a/parser/src/parser/statement.rs +++ b/parser/src/parser/statement.rs @@ -175,7 +175,7 @@ impl ParserContext { pub fn parse_conditional_statement(&mut self) -> SyntaxResult { let start = self.expect(Token::If)?; self.fuzzy_struct_state = true; - let expr = self.parse_expression_fuzzy()?; + let expr = self.parse_conditional_expression()?; self.fuzzy_struct_state = false; let body = self.parse_block()?; let next = if self.eat(Token::Else).is_some() { @@ -202,7 +202,7 @@ impl ParserContext { let start = self.parse_expression()?; self.expect(Token::DotDot)?; self.fuzzy_struct_state = true; - let stop = self.parse_expression_fuzzy()?; + let stop = self.parse_conditional_expression()?; self.fuzzy_struct_state = false; let block = self.parse_block()?; From 007cdfafbd37d8a3dd8b8f845f6498d314f2965a Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 12:50:56 -0400 Subject: [PATCH 016/108] put parse_array_expression and parse_tupple_expression as their own blocks --- parser/src/parser/expression.rs | 164 ++++++++++++++++---------------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index db4ce05f21..74a40106e1 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -541,6 +541,88 @@ impl ParserContext { })) } + pub fn parse_tupple_expression(&mut self, span: &Span) -> SyntaxResult { + if let Some((left, right, span)) = self.eat_group_partial() { + return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple( + GroupTuple { + span, + x: left, + y: right, + }, + ))))); + } + let mut args = vec![]; + let end_span; + loop { + let end = self.eat(Token::RightParen); + if let Some(end) = end { + end_span = end.span; + break; + } + let expr = self.parse_expression()?; + args.push(expr); + if self.eat(Token::Comma).is_none() { + end_span = self.expect(Token::RightParen)?; + break; + } + } + if args.len() == 1 { + Ok(args.remove(0)) + } else { + Ok(Expression::TupleInit(TupleInitExpression { + span: span + &end_span, + elements: args, + })) + } + } + + pub fn parse_array_expression(&mut self, span: &Span) -> SyntaxResult { + if let Some(end) = self.eat(Token::RightSquare) { + return Ok(Expression::ArrayInline(ArrayInlineExpression { + elements: vec![], + span: span + &end.span, + })); + } + let first = self.parse_spread_or_expression()?; + if self.eat(Token::Semicolon).is_some() { + let dimensions = self.parse_array_dimensions()?; + let end = self.expect(Token::RightSquare)?; + let first = match first { + SpreadOrExpression::Spread(first) => { + let span = span + first.span(); + return Err(SyntaxError::spread_in_array_init(&span)); + } + SpreadOrExpression::Expression(x) => x, + }; + Ok(Expression::ArrayInit(ArrayInitExpression { + span: span + &end, + element: Box::new(first), + dimensions, + })) + } else { + let end_span; + let mut elements = vec![first]; + loop { + if let Some(token) = self.eat(Token::RightSquare) { + end_span = token.span; + break; + } + if elements.len() == 1 { + self.expect(Token::Comma)?; + } + elements.push(self.parse_spread_or_expression()?); + if self.eat(Token::Comma).is_none() { + end_span = self.expect(Token::RightSquare)?; + break; + } + } + Ok(Expression::ArrayInline(ArrayInlineExpression { + elements, + span: span + &end_span, + })) + } + } + /// /// Returns an [`Expression`] AST node if the next token is a primary expression: /// - Literals: field, group, unsigned integer, signed integer, boolean, address @@ -594,86 +676,8 @@ impl ParserContext { let end = self.expect(Token::RightParen)?; Expression::Value(ValueExpression::Address(value, span + end)) } - Token::LeftParen => { - if let Some((left, right, span)) = self.eat_group_partial() { - return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple( - GroupTuple { - span, - x: left, - y: right, - }, - ))))); - } - let mut args = vec![]; - let end_span; - loop { - let end = self.eat(Token::RightParen); - if let Some(end) = end { - end_span = end.span; - break; - } - let expr = self.parse_expression()?; - args.push(expr); - if self.eat(Token::Comma).is_none() { - end_span = self.expect(Token::RightParen)?; - break; - } - } - if args.len() == 1 { - args.remove(0) - } else { - Expression::TupleInit(TupleInitExpression { - span: span + end_span, - elements: args, - }) - } - } - Token::LeftSquare => { - if let Some(end) = self.eat(Token::RightSquare) { - return Ok(Expression::ArrayInline(ArrayInlineExpression { - elements: vec![], - span: span + end.span, - })); - } - let first = self.parse_spread_or_expression()?; - if self.eat(Token::Semicolon).is_some() { - let dimensions = self.parse_array_dimensions()?; - let end = self.expect(Token::RightSquare)?; - let first = match first { - SpreadOrExpression::Spread(first) => { - let span = &span + first.span(); - return Err(SyntaxError::spread_in_array_init(&span)); - } - SpreadOrExpression::Expression(x) => x, - }; - Expression::ArrayInit(ArrayInitExpression { - span: span + end, - element: Box::new(first), - dimensions, - }) - } else { - let end_span; - let mut elements = vec![first]; - loop { - if let Some(token) = self.eat(Token::RightSquare) { - end_span = token.span; - break; - } - if elements.len() == 1 { - self.expect(Token::Comma)?; - } - elements.push(self.parse_spread_or_expression()?); - if self.eat(Token::Comma).is_none() { - end_span = self.expect(Token::RightSquare)?; - break; - } - } - Expression::ArrayInline(ArrayInlineExpression { - elements, - span: span + end_span, - }) - } - } + Token::LeftParen => self.parse_tupple_expression(&span)?, + Token::LeftSquare => self.parse_array_expression(&span)?, Token::Ident(name) => { let ident = Identifier { name, span }; if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly { From b96861feea645eca59ed4b89fac6c3ad857b55be Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 12:53:00 -0400 Subject: [PATCH 017/108] forgot function doc strings --- parser/src/parser/expression.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index 74a40106e1..c4e168fbe6 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -541,6 +541,10 @@ impl ParserContext { })) } + /// + /// Returns an [`Expression`] AST node if the next tokens represent an + /// tuple initialization expression. + /// pub fn parse_tupple_expression(&mut self, span: &Span) -> SyntaxResult { if let Some((left, right, span)) = self.eat_group_partial() { return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple( @@ -576,6 +580,10 @@ impl ParserContext { } } + /// + /// Returns an [`Expression`] AST node if the next tokens represent an + /// array initialization expression. + /// pub fn parse_array_expression(&mut self, span: &Span) -> SyntaxResult { if let Some(end) = self.eat(Token::RightSquare) { return Ok(Expression::ArrayInline(ArrayInlineExpression { From f71d77762c526f09884b9a9fe5337113aba2eaf7 Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 13:28:01 -0400 Subject: [PATCH 018/108] comment out bitwise, mod, &&= and ||= for now --- grammar/abnf-grammar.txt | 16 +-- parser/src/parser/expression.rs | 130 +++++++++++------------ parser/src/parser/statement.rs | 36 +++---- parser/src/tokenizer/lexer.rs | 84 +++++++-------- parser/src/tokenizer/mod.rs | 38 +++---- parser/src/tokenizer/token.rs | 177 ++++++++++++++++---------------- 6 files changed, 246 insertions(+), 235 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 72d970994d..30c388ca34 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -476,15 +476,15 @@ address = %s"aleo1" 58( lowercase-letter / digit ) ; whose textual representation replaces the containers ; in the printed string). ; There is an implicit extra-grammatical requirements that -; the explicit 'format-string-container' instances include +; the explicit 'formatted-string-container' instances include ; all the occurrences of '{}' in the parsed character sequence: ; that is, there may not be two contiguous 'not-double-quote' instances ; that are '{' and '}'. -format-string-container = "{}" +formatted-string-container = "{}" formatted-string = double-quote - *( not-double-quote / format-string-container ) + *( not-double-quote / formatted-string-container ) double-quote ; Here is (part of this ABNF comment), @@ -496,11 +496,11 @@ formatted-string = double-quote ; ; not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF ; -; format-string-element = not-double-quote-or-open-brace +; formatted-string-element = not-double-quote-or-open-brace ; / "{" not-double-quote-or-close-brace -; / format-string-container +; / formatted-string-container ; -; formatted-string = double-quote *format-string-element double-quote +; formatted-string = double-quote *formatted-string-element double-quote ; ; It is not immediately clear which approach is better; there are tradeoffs. ; Regardless, we should choose one eventually. @@ -652,7 +652,7 @@ token = keyword / identifier / literal / package-name - / format-string + / formatted-string / annotation-name / symbol @@ -1004,7 +1004,7 @@ assert-call = %s"assert" "(" expression ")" print-function = %s"debug" / %s"error" / %s"log" -print-arguments = "(" [ format-string *( "," expression ) ] ")" +print-arguments = "(" [ formatted-string *( "," expression ) ] ")" print-call = print-function print-arguments diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index c4e168fbe6..f0ade984b2 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -104,9 +104,9 @@ impl ParserContext { /// Otherwise, tries to parse the next token using [`parse_bit_or_expression`]. /// pub fn parse_conjunctive_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_bit_or_expression()?; + let mut expr = self.parse_equality_expression()?; while self.eat(Token::And).is_some() { - let right = self.parse_bit_or_expression()?; + let right = self.parse_equality_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: BinaryOperation::And, @@ -123,19 +123,19 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_bit_xor_expression`]. /// - pub fn parse_bit_or_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_bit_xor_expression()?; - while self.eat(Token::BitOr).is_some() { - let right = self.parse_bit_xor_expression()?; - expr = Expression::Binary(BinaryExpression { - span: expr.span() + right.span(), - op: BinaryOperation::BitOr, - left: Box::new(expr), - right: Box::new(right), - }) - } - Ok(expr) - } + // pub fn parse_bit_or_expression(&mut self) -> SyntaxResult { + // let mut expr = self.parse_bit_xor_expression()?; + // while self.eat(Token::BitOr).is_some() { + // let right = self.parse_bit_xor_expression()?; + // expr = Expression::Binary(BinaryExpression { + // span: expr.span() + right.span(), + // op: BinaryOperation::BitOr, + // left: Box::new(expr), + // right: Box::new(right), + // }) + // } + // Ok(expr) + // } /// /// Returns an [`Expression`] AST node if the next tokens represent a @@ -143,19 +143,19 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_bit_and_expression`]. /// - pub fn parse_bit_xor_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_bit_and_expression()?; - while self.eat(Token::BitXor).is_some() { - let right = self.parse_bit_and_expression()?; - expr = Expression::Binary(BinaryExpression { - span: expr.span() + right.span(), - op: BinaryOperation::BitXor, - left: Box::new(expr), - right: Box::new(right), - }) - } - Ok(expr) - } + // pub fn parse_bit_xor_expression(&mut self) -> SyntaxResult { + // let mut expr = self.parse_bit_and_expression()?; + // while self.eat(Token::BitXor).is_some() { + // let right = self.parse_bit_and_expression()?; + // expr = Expression::Binary(BinaryExpression { + // span: expr.span() + right.span(), + // op: BinaryOperation::BitXor, + // left: Box::new(expr), + // right: Box::new(right), + // }) + // } + // Ok(expr) + // } /// /// Returns an [`Expression`] AST node if the next tokens represent a @@ -163,19 +163,19 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_equality_expression`]. /// - pub fn parse_bit_and_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_equality_expression()?; - while self.eat(Token::BitAnd).is_some() { - let right = self.parse_equality_expression()?; - expr = Expression::Binary(BinaryExpression { - span: expr.span() + right.span(), - op: BinaryOperation::BitAnd, - left: Box::new(expr), - right: Box::new(right), - }) - } - Ok(expr) - } + // pub fn parse_bit_and_expression(&mut self) -> SyntaxResult { + // let mut expr = self.parse_equality_expression()?; + // while self.eat(Token::BitAnd).is_some() { + // let right = self.parse_equality_expression()?; + // expr = Expression::Binary(BinaryExpression { + // span: expr.span() + right.span(), + // op: BinaryOperation::BitAnd, + // left: Box::new(expr), + // right: Box::new(right), + // }) + // } + // Ok(expr) + // } /// /// Returns an [`Expression`] AST node if the next tokens represent a @@ -208,10 +208,10 @@ impl ParserContext { /// Otherwise, tries to parse the next token using [`parse_shift_expression`]. /// pub fn parse_ordering_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_shift_expression()?; + let mut expr = self.parse_additive_expression()?; while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Lt, Token::LtEq, Token::Gt, Token::GtEq]) { - let right = self.parse_shift_expression()?; + let right = self.parse_additive_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { @@ -234,24 +234,24 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_additive_expression`]. /// - pub fn parse_shift_expression(&mut self) -> SyntaxResult { - let mut expr = self.parse_additive_expression()?; - while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Shl, Token::Shr, Token::ShrSigned]) { - let right = self.parse_additive_expression()?; - expr = Expression::Binary(BinaryExpression { - span: expr.span() + right.span(), - op: match op { - Token::Shl => BinaryOperation::Shl, - Token::Shr => BinaryOperation::Shr, - Token::ShrSigned => BinaryOperation::ShrSigned, - _ => unimplemented!(), - }, - left: Box::new(expr), - right: Box::new(right), - }) - } - Ok(expr) - } + // pub fn parse_shift_expression(&mut self) -> SyntaxResult { + // let mut expr = self.parse_additive_expression()?; + // while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Shl, Token::Shr, Token::ShrSigned]) { + // let right = self.parse_additive_expression()?; + // expr = Expression::Binary(BinaryExpression { + // span: expr.span() + right.span(), + // op: match op { + // Token::Shl => BinaryOperation::Shl, + // Token::Shr => BinaryOperation::Shr, + // Token::ShrSigned => BinaryOperation::ShrSigned, + // _ => unimplemented!(), + // }, + // left: Box::new(expr), + // right: Box::new(right), + // }) + // } + // Ok(expr) + // } /// /// Returns an [`Expression`] AST node if the next tokens represent a @@ -285,14 +285,14 @@ impl ParserContext { /// pub fn parse_multiplicative_expression(&mut self) -> SyntaxResult { let mut expr = self.parse_exponential_expression()?; - while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Mul, Token::Div, Token::Mod]) { + while let Some(SpannedToken { token: op, .. }) = self.eat_any(&[Token::Mul, Token::Div]) { let right = self.parse_exponential_expression()?; expr = Expression::Binary(BinaryExpression { span: expr.span() + right.span(), op: match op { Token::Mul => BinaryOperation::Mul, Token::Div => BinaryOperation::Div, - Token::Mod => BinaryOperation::Mod, + // Token::Mod => BinaryOperation::Mod, _ => unimplemented!(), }, left: Box::new(expr), @@ -354,7 +354,7 @@ impl ParserContext { /// pub fn parse_unary_expression(&mut self) -> SyntaxResult { let mut ops = vec![]; - while let Some(token) = self.eat_any(&[Token::Not, Token::Minus, Token::BitNot]) { + while let Some(token) = self.eat_any(&[Token::Not, Token::Minus]) { ops.push(token); } let mut inner = self.parse_access_expression()?; @@ -362,7 +362,7 @@ impl ParserContext { let operation = match op.token { Token::Not => UnaryOperation::Not, Token::Minus => UnaryOperation::Negate, - Token::BitNot => UnaryOperation::BitNot, + // Token::BitNot => UnaryOperation::BitNot, _ => unimplemented!(), }; // hack for const signed integer overflow issues diff --git a/parser/src/parser/statement.rs b/parser/src/parser/statement.rs index 8ca277e591..72082c55dd 100644 --- a/parser/src/parser/statement.rs +++ b/parser/src/parser/statement.rs @@ -23,15 +23,15 @@ const ASSIGN_TOKENS: &[Token] = &[ Token::MulEq, Token::DivEq, Token::ExpEq, - Token::BitAndEq, - Token::BitOrEq, - Token::BitXorEq, - Token::ShlEq, - Token::ShrEq, - Token::ShrSignedEq, - Token::ModEq, - Token::OrEq, - Token::AndEq, + // Token::BitAndEq, + // Token::BitOrEq, + // Token::BitXorEq, + // Token::ShlEq, + // Token::ShrEq, + // Token::ShrSignedEq, + // Token::ModEq, + // Token::OrEq, + // Token::AndEq, ]; impl ParserContext { @@ -110,15 +110,15 @@ impl ParserContext { Token::MulEq => AssignOperation::Mul, Token::DivEq => AssignOperation::Div, Token::ExpEq => AssignOperation::Pow, - Token::OrEq => AssignOperation::Or, - Token::AndEq => AssignOperation::And, - Token::BitOrEq => AssignOperation::BitOr, - Token::BitAndEq => AssignOperation::BitAnd, - Token::BitXorEq => AssignOperation::BitXor, - Token::ShrEq => AssignOperation::Shr, - Token::ShrSignedEq => AssignOperation::ShrSigned, - Token::ShlEq => AssignOperation::Shl, - Token::ModEq => AssignOperation::Mod, + // Token::OrEq => AssignOperation::Or, + // Token::AndEq => AssignOperation::And, + // Token::BitOrEq => AssignOperation::BitOr, + // Token::BitAndEq => AssignOperation::BitAnd, + // Token::BitXorEq => AssignOperation::BitXor, + // Token::ShrEq => AssignOperation::Shr, + // Token::ShrSignedEq => AssignOperation::ShrSigned, + // Token::ShlEq => AssignOperation::Shl, + // Token::ModEq => AssignOperation::Mod, _ => unimplemented!(), }, value, diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index d3b04e54d9..2d1aa1afd0 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -163,14 +163,15 @@ impl Token { } b'&' => { if let Some(input) = eat(input, "&&") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::AndEq)); - } + // if let Some(input) = eat(input, "=") { + // return (input, Some(Token::AndEq)); + // } return (input, Some(Token::And)); - } else if let Some(input) = eat(input, "&=") { - return (input, Some(Token::BitAndEq)); } - return (&input[1..], Some(Token::BitAnd)); + // else if let Some(input) = eat(input, "&=") { + // return (input, Some(Token::BitAndEq)); + // } + // return (&input[1..], Some(Token::BitAnd)); } b'(' => return (&input[1..], Some(Token::LeftParen)), b')' => return (&input[1..], Some(Token::RightParen)), @@ -250,28 +251,30 @@ impl Token { b'<' => { if let Some(input) = eat(input, "<=") { return (input, Some(Token::LtEq)); - } else if let Some(input) = eat(input, "<<") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShlEq)); - } - return (input, Some(Token::Shl)); } + // else if let Some(input) = eat(input, "<<") { + // if let Some(input) = eat(input, "=") { + // return (input, Some(Token::ShlEq)); + // } + // return (input, Some(Token::Shl)); + // } return (&input[1..], Some(Token::Lt)); } b'>' => { if let Some(input) = eat(input, ">=") { return (input, Some(Token::GtEq)); - } else if let Some(input) = eat(input, ">>") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShrEq)); - } else if let Some(input) = eat(input, ">") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShrSignedEq)); - } - return (input, Some(Token::ShrSigned)); - } - return (input, Some(Token::Shr)); } + // else if let Some(input) = eat(input, ">>") { + // if let Some(input) = eat(input, "=") { + // return (input, Some(Token::ShrEq)); + // } else if let Some(input) = eat(input, ">") { + // if let Some(input) = eat(input, "=") { + // return (input, Some(Token::ShrSignedEq)); + // } + // return (input, Some(Token::ShrSigned)); + // } + // return (input, Some(Token::Shr)); + // } return (&input[1..], Some(Token::Gt)); } b'=' => { @@ -288,28 +291,29 @@ impl Token { b'}' => return (&input[1..], Some(Token::RightCurly)), b'|' => { if let Some(input) = eat(input, "||") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::OrEq)); - } + // if let Some(input) = eat(input, "=") { + // return (input, Some(Token::OrEq)); + // } return (input, Some(Token::Or)); - } else if let Some(input) = eat(input, "|=") { - return (input, Some(Token::BitOrEq)); } - return (&input[1..], Some(Token::BitOr)); - } - b'^' => { - if let Some(input) = eat(input, "^=") { - return (input, Some(Token::BitXorEq)); - } - return (&input[1..], Some(Token::BitXor)); - } - b'~' => return (&input[1..], Some(Token::BitNot)), - b'%' => { - if let Some(input) = eat(input, "%=") { - return (input, Some(Token::ModEq)); - } - return (&input[1..], Some(Token::Mod)); + // else if let Some(input) = eat(input, "|=") { + // return (input, Some(Token::BitOrEq)); + // } + // return (&input[1..], Some(Token::BitOr)); } + // b'^' => { + // if let Some(input) = eat(input, "^=") { + // return (input, Some(Token::BitXorEq)); + // } + // return (&input[1..], Some(Token::BitXor)); + // } + // b'~' => return (&input[1..], Some(Token::BitNot)), + // b'%' => { + // if let Some(input) = eat(input, "%=") { + // return (input, Some(Token::ModEq)); + // } + // return (&input[1..], Some(Token::Mod)); + // } _ => (), } if let Some((ident, input)) = eat_identifier(input) { diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 1d4848f7d4..ef333e1711 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -107,6 +107,24 @@ mod tests { #[test] fn test_tokenizer() { + // & + // &= + // | + // |= + // ^ + // ^= + // ~ + // << + // <<= + // >> + // >>= + // >>> + // >>>= + // % + // %= + // ||= + // &&= + let tokens = tokenize( "test_path", r#" @@ -193,23 +211,6 @@ mod tests { {{ }} || - & - &= - | - |= - ^ - ^= - ~ - << - <<= - >> - >>= - >>> - >>>= - % - %= - ||= - &&= ? // test /* test */ @@ -220,9 +221,10 @@ mod tests { for SpannedToken { token, .. } in tokens.iter() { output += &format!("{} ", &token.to_string()); } + // & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= assert_eq!( output, - r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= ? // test + r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test /* test */ // "# ); diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index 3af070fe26..46877c7ce6 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -127,25 +127,24 @@ pub enum Token { Return, Static, String, - // Not yet in ABNF - BitAnd, - BitAndEq, - BitOr, - BitOrEq, - BitXor, - BitXorEq, - BitNot, - Shl, - ShlEq, - Shr, - ShrEq, - ShrSigned, - ShrSignedEq, - Mod, - ModEq, - OrEq, - AndEq, + // BitAnd, + // BitAndEq, + // BitOr, + // BitOrEq, + // BitXor, + // BitXorEq, + // BitNot, + // Shl, + // ShlEq, + // Shr, + // ShrEq, + // ShrSigned, + // ShrSignedEq, + // Mod, + // ModEq, + // OrEq, + // AndEq, } /// Represents all valid Leo keyword tokens. @@ -199,6 +198,8 @@ impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Token::*; match self { + CommentLine(s) => writeln!(f, "{}", s), + CommentBlock(s) => write!(f, "{}", s), FormattedString(parts) => { // todo escapes write!(f, "\"")?; @@ -207,99 +208,103 @@ impl fmt::Display for Token { } write!(f, "\"") } - AddressLit(s) => write!(f, "{}", s), Ident(s) => write!(f, "{}", s), Int(s) => write!(f, "{}", s), - CommentLine(s) => writeln!(f, "{}", s), - CommentBlock(s) => write!(f, "{}", s), + True => write!(f, "true"), + False => write!(f, "false"), + AddressLit(s) => write!(f, "{}", s), + + At => write!(f, "@"), + Not => write!(f, "!"), - NotEq => write!(f, "!="), And => write!(f, "&&"), + Or => write!(f, "||"), + Eq => write!(f, "=="), + NotEq => write!(f, "!="), + Lt => write!(f, "<"), + LtEq => write!(f, "<="), + Gt => write!(f, ">"), + GtEq => write!(f, ">="), + Add => write!(f, "+"), + Minus => write!(f, "-"), + Mul => write!(f, "*"), + Div => write!(f, "/"), + Exp => write!(f, "**"), + Assign => write!(f, "="), + AddEq => write!(f, "+="), + MinusEq => write!(f, "-="), + MulEq => write!(f, "*="), + DivEq => write!(f, "/="), + ExpEq => write!(f, "**="), LeftParen => write!(f, "("), RightParen => write!(f, ")"), - Mul => write!(f, "*"), - Exp => write!(f, "**"), - ExpEq => write!(f, "**="), - MulEq => write!(f, "*="), - Add => write!(f, "+"), - AddEq => write!(f, "+="), + LeftSquare => write!(f, "["), + RightSquare => write!(f, "]"), + LeftCurly => write!(f, "{{"), + RightCurly => write!(f, "}}"), Comma => write!(f, ","), - Minus => write!(f, "-"), - MinusEq => write!(f, "-="), - Arrow => write!(f, "->"), Dot => write!(f, "."), DotDot => write!(f, ".."), DotDotDot => write!(f, "..."), - Div => write!(f, "/"), - DivEq => write!(f, "/="), + Semicolon => write!(f, ";"), Colon => write!(f, ":"), DoubleColon => write!(f, "::"), - Semicolon => write!(f, ";"), - Lt => write!(f, "<"), - LtEq => write!(f, "<="), - Assign => write!(f, "="), - Eq => write!(f, "=="), - Gt => write!(f, ">"), - GtEq => write!(f, ">="), - At => write!(f, "@"), - LeftSquare => write!(f, "["), - RightSquare => write!(f, "]"), - Address => write!(f, "address"), - As => write!(f, "as"), + Question => write!(f, "?"), + Arrow => write!(f, "->"), + Underscore => write!(f, "_"), + + U8 => write!(f, "u8"), + U16 => write!(f, "u16"), + U32 => write!(f, "u32"), + U64 => write!(f, "u64"), + U128 => write!(f, "u128"), + I8 => write!(f, "i8"), + I16 => write!(f, "i16"), + I32 => write!(f, "i32"), + I64 => write!(f, "i64"), + I128 => write!(f, "i128"), + Field => write!(f, "field"), + Group => write!(f, "group"), Bool => write!(f, "bool"), + Address => write!(f, "address"), + BigSelf => write!(f, "Self"), + + Input => write!(f, "input"), + LittleSelf => write!(f, "self"), + + Import => write!(f, "import"), + + As => write!(f, "as"), Circuit => write!(f, "circuit"), + Console => write!(f, "console"), Const => write!(f, "const"), Else => write!(f, "else"), - False => write!(f, "false"), - Field => write!(f, "field"), For => write!(f, "for"), Function => write!(f, "function"), - Group => write!(f, "group"), - I128 => write!(f, "i128"), - I64 => write!(f, "i64"), - I32 => write!(f, "i32"), - I16 => write!(f, "i16"), - I8 => write!(f, "i8"), If => write!(f, "if"), - Import => write!(f, "import"), In => write!(f, "in"), - Input => write!(f, "input"), Let => write!(f, "let"), Mut => write!(f, "mut"), Return => write!(f, "return"), Static => write!(f, "static"), String => write!(f, "string"), - True => write!(f, "true"), - U128 => write!(f, "u128"), - U64 => write!(f, "u64"), - U32 => write!(f, "u32"), - U16 => write!(f, "u16"), - U8 => write!(f, "u8"), - BigSelf => write!(f, "Self"), - LittleSelf => write!(f, "self"), - Console => write!(f, "console"), - LeftCurly => write!(f, "{{"), - RightCurly => write!(f, "}}"), - Or => write!(f, "||"), - BitAnd => write!(f, "&"), - BitAndEq => write!(f, "&="), - BitOr => write!(f, "|"), - BitOrEq => write!(f, "|="), - BitXor => write!(f, "^"), - BitXorEq => write!(f, "^="), - BitNot => write!(f, "~"), - Shl => write!(f, "<<"), - ShlEq => write!(f, "<<="), - Shr => write!(f, ">>"), - ShrEq => write!(f, ">>="), - ShrSigned => write!(f, ">>>"), - ShrSignedEq => write!(f, ">>>="), - Mod => write!(f, "%"), - ModEq => write!(f, "%="), - OrEq => write!(f, "||="), - AndEq => write!(f, "&&="), - Question => write!(f, "?"), - Underscore => write!(f, "_"), + // BitAnd => write!(f, "&"), + // BitAndEq => write!(f, "&="), + // BitOr => write!(f, "|"), + // BitOrEq => write!(f, "|="), + // BitXor => write!(f, "^"), + // BitXorEq => write!(f, "^="), + // BitNot => write!(f, "~"), + // Shl => write!(f, "<<"), + // ShlEq => write!(f, "<<="), + // Shr => write!(f, ">>"), + // ShrEq => write!(f, ">>="), + // ShrSigned => write!(f, ">>>"), + // ShrSignedEq => write!(f, ">>>="), + // Mod => write!(f, "%"), + // ModEq => write!(f, "%="), + // OrEq => write!(f, "||="), + // AndEq => write!(f, "&&="), } } } From 5ae7771050b48eed864004e1043afbb96680fd6e Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 13:38:45 -0400 Subject: [PATCH 019/108] cast-expression in abnf --- grammar/abnf-grammar.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 30c388ca34..9c7bdefd8f 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -855,14 +855,19 @@ unary-expression = primary-expression / "!" unary-expression / "-" unary-expression +; Next in the operator precedence is casting. +; The current rule below makes exponentiation left-associative, +cast-expression = unary-expression + / cast-expression %s"as" type + ; Next in the operator precedence is exponentiation, ; following mathematical practice. ; The current rule below makes exponentiation left-associative, ; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. ; This is easy to change if we want it to be right-associative instead. -exponential-expression = unary-expression - / exponential-expression "**" unary-expression +exponential-expression = cast-expression + / exponential-expression "**" cast-expression ; Next in precedence come multiplication and division, both left-associative. @@ -902,16 +907,12 @@ conjunctive-expression = equality-expression disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression -; Next come conditional expressions. +; Finally we have conditional expressions. conditional-expression = disjunctive-expression / conditional-expression "?" expression ":" conditional-expression - -; Need to decide on operator precedence for as. -cast-expression = conditional-expression - / cast-expression %s"as" type ; These are all the expressions. ; Recall that conditional expressions From 5ed7582b22a1db10362889f4c366f5b7920c55ea Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 13:54:53 -0400 Subject: [PATCH 020/108] tentative parse expression grammar rule --- grammar/abnf-grammar.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 9c7bdefd8f..a93884bbcf 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -823,9 +823,7 @@ circuit-construction = circuit-type "{" circuit-inline-element = identifier ":" expression / identifier -circuit-access = primary-expression "." identifier - -circuit-expression = circuit-construction / circuit-access +circuit-expression = circuit-construction ; There are three kinds of function calls: ; top-level function calls, @@ -847,11 +845,16 @@ function-call = top-level-function-call function-arguments = "(" [ expression *( "," expression ) ] ")" -; Unary operators have the highest precedence. -; They apply to primary expressions +; Access expressions have highest precedence. +; They apply to primary expressions. +access-expression = primary-expression + / access-expression "." identifier + +; Unary operators have the highest operator precedence. +; They apply to access expressions ; and recursively to unary expressions. -unary-expression = primary-expression +unary-expression = access-expression / "!" unary-expression / "-" unary-expression From 3571fa2080c929aa1918131cb916bf73bfcd1563 Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 15:25:56 -0400 Subject: [PATCH 021/108] I think this is the best way to handle access_expressions in ABNF to reflect the parser --- grammar/abnf-grammar.txt | 29 ++++++++++------------------- parser/src/parser/expression.rs | 4 ++-- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index a93884bbcf..cef8e21b66 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -767,7 +767,7 @@ primary-expression = identifier tuple-construction = "(" [ expression 1*( "," expression ) ] ")" -tuple-access = primary-expression "." natural + tuple-expression = tuple-construction / tuple-access @@ -797,13 +797,7 @@ array-repeat-construction = "[" expression ";" array-dimensions "]" array-construction = array-inline-construction / array-repeat-construction -array-element-access = primary-expression "[" expression "]" - -array-range-access = primary-expression "[" [expression] ".." [expression] "]" - -array-access = array-element-access / array-range-access - -array-expression = array-construction / array-access +array-expression = array-construction ; There are circuit expressions to construct and deconstruct circuit values. ; A construction lists values for all the member variables (in any order); @@ -832,23 +826,20 @@ circuit-expression = circuit-construction ; What changes is the start, but they all end in an argument list, ; delimited by a closing parenthesis. -top-level-function-call = identifier function-arguments - -instance-member-function-call = primary-expression "." - identifier function-arguments - -static-member-function-call = circuit-type "::" identifier function-arguments - -function-call = top-level-function-call - / instance-member-function-call - / static-member-function-call - function-arguments = "(" [ expression *( "," expression ) ] ")" ; Access expressions have highest precedence. ; They apply to primary expressions. +; Contains access expressions for arrays, tuples, and circuits. +; Contains function call types. access-expression = primary-expression + / access-expression "." natural / access-expression "." identifier + / identifier function-arguments + / access-expression "." identifier function-arguments + / circuit-type "::" identifier function-arguments + / access-expression "[" expression "]" + / access-expression "[" [expression] ".." [expression] "]" ; Unary operators have the highest operator precedence. ; They apply to access expressions diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index f0ade984b2..b0cdb5d6a6 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -545,7 +545,7 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent an /// tuple initialization expression. /// - pub fn parse_tupple_expression(&mut self, span: &Span) -> SyntaxResult { + pub fn parse_tuple_expression(&mut self, span: &Span) -> SyntaxResult { if let Some((left, right, span)) = self.eat_group_partial() { return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple( GroupTuple { @@ -684,7 +684,7 @@ impl ParserContext { let end = self.expect(Token::RightParen)?; Expression::Value(ValueExpression::Address(value, span + end)) } - Token::LeftParen => self.parse_tupple_expression(&span)?, + Token::LeftParen => self.parse_tuple_expression(&span)?, Token::LeftSquare => self.parse_array_expression(&span)?, Token::Ident(name) => { let ident = Identifier { name, span }; From 50b37d2672fb4c39455a5e726e04951c6b501a8e Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 24 Mar 2021 15:33:03 -0400 Subject: [PATCH 022/108] parse_assign_statment --- parser/src/parser/statement.rs | 79 ++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/parser/src/parser/statement.rs b/parser/src/parser/statement.rs index 72082c55dd..463fc05044 100644 --- a/parser/src/parser/statement.rs +++ b/parser/src/parser/statement.rs @@ -93,44 +93,49 @@ impl ParserContext { Token::Console => Ok(Statement::Console(self.parse_console_statement()?)), Token::Let | Token::Const => Ok(Statement::Definition(self.parse_definition_statement()?)), Token::LeftCurly => Ok(Statement::Block(self.parse_block()?)), - _ => { - let expr = self.parse_expression()?; + _ => Ok(self.parse_assign_statement()?), + } + } - if let Some(operator) = self.eat_any(ASSIGN_TOKENS) { - let value = self.parse_expression()?; - let assignee = Self::construct_assignee(expr)?; - self.expect(Token::Semicolon)?; - Ok(Statement::Assign(AssignStatement { - span: &assignee.span + value.span(), - assignee, - operation: match operator.token { - Token::Assign => AssignOperation::Assign, - Token::AddEq => AssignOperation::Add, - Token::MinusEq => AssignOperation::Sub, - Token::MulEq => AssignOperation::Mul, - Token::DivEq => AssignOperation::Div, - Token::ExpEq => AssignOperation::Pow, - // Token::OrEq => AssignOperation::Or, - // Token::AndEq => AssignOperation::And, - // Token::BitOrEq => AssignOperation::BitOr, - // Token::BitAndEq => AssignOperation::BitAnd, - // Token::BitXorEq => AssignOperation::BitXor, - // Token::ShrEq => AssignOperation::Shr, - // Token::ShrSignedEq => AssignOperation::ShrSigned, - // Token::ShlEq => AssignOperation::Shl, - // Token::ModEq => AssignOperation::Mod, - _ => unimplemented!(), - }, - value, - })) - } else { - self.expect(Token::Semicolon)?; - Ok(Statement::Expression(ExpressionStatement { - span: expr.span().clone(), - expression: expr, - })) - } - } + /// + /// Returns a [`Block`] AST node if the next tokens represent a assign, or expression statement. + /// + pub fn parse_assign_statement(&mut self) -> SyntaxResult { + let expr = self.parse_expression()?; + + if let Some(operator) = self.eat_any(ASSIGN_TOKENS) { + let value = self.parse_expression()?; + let assignee = Self::construct_assignee(expr)?; + self.expect(Token::Semicolon)?; + Ok(Statement::Assign(AssignStatement { + span: &assignee.span + value.span(), + assignee, + operation: match operator.token { + Token::Assign => AssignOperation::Assign, + Token::AddEq => AssignOperation::Add, + Token::MinusEq => AssignOperation::Sub, + Token::MulEq => AssignOperation::Mul, + Token::DivEq => AssignOperation::Div, + Token::ExpEq => AssignOperation::Pow, + // Token::OrEq => AssignOperation::Or, + // Token::AndEq => AssignOperation::And, + // Token::BitOrEq => AssignOperation::BitOr, + // Token::BitAndEq => AssignOperation::BitAnd, + // Token::BitXorEq => AssignOperation::BitXor, + // Token::ShrEq => AssignOperation::Shr, + // Token::ShrSignedEq => AssignOperation::ShrSigned, + // Token::ShlEq => AssignOperation::Shl, + // Token::ModEq => AssignOperation::Mod, + _ => unimplemented!(), + }, + value, + })) + } else { + self.expect(Token::Semicolon)?; + Ok(Statement::Expression(ExpressionStatement { + span: expr.span().clone(), + expression: expr, + })) } } From 001056f8bde0cd5dfd7c804d532e674da85ae896 Mon Sep 17 00:00:00 2001 From: gluax Date: Thu, 25 Mar 2021 14:34:16 -0400 Subject: [PATCH 023/108] rename-access expression rule and parse function to postfix --- grammar/abnf-grammar.txt | 18 +++++++++--------- parser/src/parser/expression.rs | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index cef8e21b66..833056a532 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -828,24 +828,24 @@ circuit-expression = circuit-construction function-arguments = "(" [ expression *( "," expression ) ] ")" -; Access expressions have highest precedence. +; Postfix expressions have highest precedence. ; They apply to primary expressions. ; Contains access expressions for arrays, tuples, and circuits. ; Contains function call types. -access-expression = primary-expression - / access-expression "." natural - / access-expression "." identifier +postfix-expression = primary-expression + / postfix-expression "." natural + / postfix-expression "." identifier / identifier function-arguments - / access-expression "." identifier function-arguments + / postfix-expression "." identifier function-arguments / circuit-type "::" identifier function-arguments - / access-expression "[" expression "]" - / access-expression "[" [expression] ".." [expression] "]" + / postfix-expression "[" expression "]" + / postfix-expression "[" [expression] ".." [expression] "]" ; Unary operators have the highest operator precedence. -; They apply to access expressions +; They apply to postfix expressions ; and recursively to unary expressions. -unary-expression = access-expression +unary-expression = postfix-expression / "!" unary-expression / "-" unary-expression diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index b0cdb5d6a6..d447c389de 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -350,14 +350,14 @@ impl ParserContext { /// Returns an [`Expression`] AST node if the next tokens represent a /// unary not, negate, or bitwise not expression. /// - /// Otherwise, tries to parse the next token using [`parse_access_expression`]. + /// Otherwise, tries to parse the next token using [`parse_postfix_expression`]. /// pub fn parse_unary_expression(&mut self) -> SyntaxResult { let mut ops = vec![]; while let Some(token) = self.eat_any(&[Token::Not, Token::Minus]) { ops.push(token); } - let mut inner = self.parse_access_expression()?; + let mut inner = self.parse_postfix_expression()?; for op in ops.into_iter().rev() { let operation = match op.token { Token::Not => UnaryOperation::Not, @@ -390,7 +390,7 @@ impl ParserContext { /// /// Otherwise, tries to parse the next token using [`parse_primary_expression`]. /// - pub fn parse_access_expression(&mut self) -> SyntaxResult { + pub fn parse_postfix_expression(&mut self) -> SyntaxResult { let mut expr = self.parse_primary_expression()?; while let Some(token) = self.eat_any(&[Token::LeftSquare, Token::Dot, Token::LeftParen, Token::DoubleColon]) { match token.token { From f9d8f48577714459c2b9c6aee540a9e57fab8a32 Mon Sep 17 00:00:00 2001 From: gluax Date: Thu, 25 Mar 2021 16:24:01 -0400 Subject: [PATCH 024/108] clean up last bit of leftover access --- grammar/abnf-grammar.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 833056a532..a397d1630b 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -767,9 +767,7 @@ primary-expression = identifier tuple-construction = "(" [ expression 1*( "," expression ) ] ")" - - -tuple-expression = tuple-construction / tuple-access +tuple-expression = tuple-construction ; The are array expressions to construct and deconstruct arrays. ; There are two kinds of constructions: From 5985d8da41ca5b684703496e72d272f80e450837 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 22 Mar 2021 06:48:48 -0700 Subject: [PATCH 025/108] tendrilize spans --- Cargo.lock | 42 +++ asg/Cargo.toml | 3 + asg/src/checks/return_path.rs | 9 +- asg/src/const_value.rs | 7 +- asg/src/error/mod.rs | 20 +- asg/src/expression/array_init.rs | 2 +- asg/src/expression/call.rs | 19 +- asg/src/expression/circuit_access.rs | 29 +-- asg/src/expression/circuit_init.rs | 21 +- asg/src/expression/constant.rs | 24 +- asg/src/expression/tuple_access.rs | 2 +- asg/src/expression/variable_ref.rs | 18 +- asg/src/input.rs | 6 +- asg/src/node.rs | 11 +- asg/src/program/circuit.rs | 14 +- asg/src/program/function.rs | 20 +- asg/src/program/mod.rs | 30 +-- asg/src/scope.rs | 2 +- asg/src/statement/assign.rs | 24 +- asg/src/statement/definition.rs | 16 +- asg/src/statement/iteration.rs | 13 +- asg/src/type_.rs | 4 +- ast/Cargo.toml | 3 + ast/src/annotation.rs | 4 +- ast/src/common/array_dimensions.rs | 2 +- ast/src/common/identifier.rs | 32 +-- ast/src/common/mod.rs | 4 + ast/src/common/positive_number.rs | 10 +- ast/src/common/span.rs | 56 ++-- ast/src/common/tendril_json.rs | 26 ++ ast/src/common/vec_tendril_json.rs | 33 +++ ast/src/errors/error.rs | 85 ++----- ast/src/errors/mod.rs | 6 +- ast/src/expression/mod.rs | 8 +- ast/src/expression/value.rs | 16 +- ast/src/groups/group_coordinate.rs | 12 +- ast/src/groups/group_value.rs | 9 +- ast/src/imports/import_symbol.rs | 4 +- ast/src/input/input.rs | 4 +- ast/src/input/program_input/program_input.rs | 4 +- .../public_state/public_state.rs | 6 +- ast/src/reducer/canonicalization.rs | 2 +- .../statements/console/formatted_string.rs | 3 +- ast/src/types/integer_type.rs | 3 +- ast/src/types/type_.rs | 5 +- compiler/src/compiler.rs | 75 +----- compiler/src/console/assert.rs | 6 +- compiler/src/constraints/constraints.rs | 14 +- compiler/src/errors/compiler.rs | 28 +- compiler/src/errors/console.rs | 16 +- compiler/src/errors/expression.rs | 28 +- compiler/src/errors/function.rs | 45 +--- compiler/src/errors/import.rs | 14 +- compiler/src/errors/output_bytes.rs | 18 +- compiler/src/errors/statement.rs | 26 +- compiler/src/errors/value/address.rs | 14 +- compiler/src/errors/value/boolean.rs | 14 +- compiler/src/errors/value/field.rs | 14 +- compiler/src/errors/value/group.rs | 14 +- compiler/src/errors/value/integer.rs | 14 +- compiler/src/errors/value/value.rs | 24 +- compiler/src/expression/circuit/circuit.rs | 2 +- compiler/src/expression/expression.rs | 5 +- compiler/src/function/input/input_keyword.rs | 10 +- compiler/src/function/input/input_section.rs | 2 +- .../src/function/input/main_function_input.rs | 4 +- compiler/src/function/main_function.rs | 10 +- compiler/src/function/mut_target.rs | 16 +- compiler/src/function/result/result.rs | 6 +- compiler/src/output/output_file.rs | 3 +- compiler/src/prelude/blake2s.rs | 2 +- .../src/statement/conditional/conditional.rs | 8 +- compiler/src/statement/iteration/iteration.rs | 6 +- compiler/src/value/address/address.rs | 6 +- compiler/src/value/field/field_type.rs | 6 +- .../src/value/group/targets/edwards_bls12.rs | 9 +- compiler/src/value/integer/macros.rs | 7 + compiler/tests/array/mod.rs | 7 +- compiler/tests/boolean/mod.rs | 7 +- compiler/tests/console/mod.rs | 6 +- .../core/packages/unstable/blake2s/mod.rs | 7 +- compiler/tests/integers/i128/mod.rs | 5 +- compiler/tests/integers/i16/mod.rs | 5 +- compiler/tests/integers/i32/mod.rs | 5 +- compiler/tests/integers/i64/mod.rs | 5 +- compiler/tests/integers/i8/mod.rs | 5 +- compiler/tests/integers/u128/mod.rs | 6 +- compiler/tests/integers/u16/mod.rs | 6 +- compiler/tests/integers/u32/mod.rs | 6 +- compiler/tests/integers/u64/mod.rs | 6 +- compiler/tests/integers/u8/mod.rs | 6 +- compiler/tests/mod.rs | 5 +- compiler/tests/statements/conditional/mod.rs | 10 +- imports/src/errors/import_parser.rs | 20 +- leo/api.rs | 3 +- leo/commands/package/clone.rs | 3 +- leo/config.rs | 4 +- leo/main.rs | 25 +- leo/tests/mod.rs | 9 +- package/src/inputs/input.rs | 3 +- package/src/inputs/state.rs | 3 +- package/src/outputs/checksum.rs | 3 +- package/src/outputs/circuit.rs | 3 +- package/src/outputs/proof.rs | 3 +- package/src/outputs/proving_key.rs | 3 +- package/src/outputs/verification_key.rs | 3 +- package/src/root/zip.rs | 11 +- package/tests/mod.rs | 3 +- parser/Cargo.toml | 3 + parser/src/errors/deprecated.rs | 14 +- parser/src/errors/syntax.rs | 18 +- parser/src/errors/token.rs | 14 +- parser/src/parser/context.rs | 7 +- parser/src/parser/expression.rs | 21 +- parser/src/parser/file.rs | 59 +++-- parser/src/parser/mod.rs | 13 +- parser/src/tokenizer/lexer.rs | 240 +++++++++--------- parser/src/tokenizer/mod.rs | 60 +++-- parser/src/tokenizer/token.rs | 15 +- .../tests/serialization/expected_leo_ast.json | 22 +- state/src/utilities/input_value.rs | 2 +- .../test_verify_local_data_commitment.rs | 16 +- 122 files changed, 668 insertions(+), 1171 deletions(-) create mode 100644 ast/src/common/tendril_json.rs create mode 100644 ast/src/common/vec_tendril_json.rs diff --git a/Cargo.lock b/Cargo.lock index 4ec3ace7a3..520a984b45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,6 +787,16 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "futf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures-channel" version = "0.3.13" @@ -1203,6 +1213,7 @@ dependencies = [ "num-bigint", "serde", "serde_json", + "tendril", "thiserror", "typed-arena", ] @@ -1225,6 +1236,7 @@ dependencies = [ "pest", "serde", "serde_json", + "tendril", "thiserror", ] @@ -1351,6 +1363,7 @@ dependencies = [ "leo-ast", "serde", "serde_json", + "tendril", "thiserror", "tracing", ] @@ -1444,6 +1457,12 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + [[package]] name = "maplit" version = "1.0.2" @@ -1610,6 +1629,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "nias" version = "0.5.0" @@ -2759,6 +2784,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "tendril" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -3077,6 +3113,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" + [[package]] name = "vcpkg" version = "0.2.11" diff --git a/asg/Cargo.toml b/asg/Cargo.toml index 59991f521e..e20f56e7fd 100644 --- a/asg/Cargo.toml +++ b/asg/Cargo.toml @@ -43,5 +43,8 @@ version = "0.4" [dependencies.typed-arena] version = "2.0" +[dependencies.tendril] +version = "0.4" + [dev-dependencies.criterion] version = "0.3" diff --git a/asg/src/checks/return_path.rs b/asg/src/checks/return_path.rs index 8a21f0514e..ae38417731 100644 --- a/asg/src/checks/return_path.rs +++ b/asg/src/checks/return_path.rs @@ -15,14 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - statement::*, - BoolAnd, - Expression, - Monoid, - MonoidalReducerExpression, - MonoidalReducerStatement, - Node, - Span, + statement::*, BoolAnd, Expression, Monoid, MonoidalReducerExpression, MonoidalReducerStatement, Node, Span, }; pub struct ReturnPathReducer { diff --git a/asg/src/const_value.rs b/asg/src/const_value.rs index c0ddb90d07..6f453839e1 100644 --- a/asg/src/const_value.rs +++ b/asg/src/const_value.rs @@ -18,6 +18,7 @@ use crate::{AsgConvertError, IntegerType, Span, Type}; use num_bigint::BigInt; use std::{convert::TryInto, fmt}; +use tendril::StrTendril; /// Constant integer values in a program. #[derive(Clone, Debug, PartialEq)] @@ -38,7 +39,7 @@ pub enum ConstInt { #[derive(Clone, Debug, PartialEq)] pub enum GroupCoordinate { /// Explicit field element number string. - Number(String), + Number(StrTendril), /// Attempt to recover with a sign high bit. SignHigh, @@ -87,7 +88,7 @@ impl Into for &GroupCoordinate { #[derive(Clone, Debug, PartialEq)] pub enum GroupValue { - Single(String), + Single(StrTendril), Tuple(GroupCoordinate, GroupCoordinate), } @@ -106,7 +107,7 @@ pub enum ConstValue { Int(ConstInt), Group(GroupValue), Field(BigInt), - Address(String), + Address(StrTendril), Boolean(bool), // compounds diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index 87040a58fa..4a8b9143d5 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -35,25 +35,7 @@ pub enum AsgConvertError { SyntaxError(#[from] SyntaxError), } -impl LeoError for AsgConvertError { - fn get_path(&self) -> Option<&str> { - match self { - AsgConvertError::Error(error) => error.get_path(), - AsgConvertError::SyntaxError(error) => error.get_path(), - AsgConvertError::ImportError(error) => error.get_path(), - AsgConvertError::InternalError(_) => None, - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - AsgConvertError::Error(error) => error.set_path(path, contents), - AsgConvertError::SyntaxError(error) => error.set_path(path, contents), - AsgConvertError::ImportError(error) => error.set_path(path, contents), - AsgConvertError::InternalError(_) => {} - } - } -} +impl LeoError for AsgConvertError {} impl AsgConvertError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/asg/src/expression/array_init.rs b/asg/src/expression/array_init.rs index 0444e23be1..92fdd6ba72 100644 --- a/asg/src/expression/array_init.rs +++ b/asg/src/expression/array_init.rs @@ -152,7 +152,7 @@ impl<'a> Into for &ArrayInitExpression<'a> { leo_ast::ArrayInitExpression { element: Box::new(self.element.get().into()), dimensions: leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber { - value: self.len.to_string(), + value: self.len.to_string().into(), }]), span: self.span.clone().unwrap_or_default(), } diff --git a/asg/src/expression/call.rs b/asg/src/expression/call.rs index 8c91f86da5..dfb3fbfaff 100644 --- a/asg/src/expression/call.rs +++ b/asg/src/expression/call.rs @@ -15,19 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - CircuitMember, - ConstValue, - Expression, - ExpressionNode, - FromAst, - Function, - FunctionQualifier, - Node, - PartialType, - Scope, - Span, - Type, + AsgConvertError, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Function, FunctionQualifier, Node, + PartialType, Scope, Span, Type, }; pub use leo_ast::{BinaryOperation, Node as AstNode}; @@ -116,7 +105,7 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> { let circuit_name = circuit.name.borrow().name.clone(); let member = circuit.members.borrow(); let member = member - .get(&name.name) + .get(name.name.as_ref()) .ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?; match member { CircuitMember::Function(body) => { @@ -156,7 +145,7 @@ impl<'a> FromAst<'a, leo_ast::CallExpression> for CallExpression<'a> { let member = circuit.members.borrow(); let member = member - .get(&name.name) + .get(name.name.as_ref()) .ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit_name, &name.name, span))?; match member { CircuitMember::Function(body) => { diff --git a/asg/src/expression/circuit_access.rs b/asg/src/expression/circuit_access.rs index 739579cabd..42256682b1 100644 --- a/asg/src/expression/circuit_access.rs +++ b/asg/src/expression/circuit_access.rs @@ -15,19 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - Circuit, - CircuitMember, - ConstValue, - Expression, - ExpressionNode, - FromAst, - Identifier, - Node, - PartialType, - Scope, - Span, - Type, + AsgConvertError, Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, + PartialType, Scope, Span, Type, }; use std::cell::Cell; @@ -67,7 +56,7 @@ impl<'a> ExpressionNode<'a> for CircuitAccessExpression<'a> { None // function target only for static } else { let members = self.circuit.get().members.borrow(); - let member = members.get(&self.member.name)?; + let member = members.get(self.member.name.as_ref())?; match member { CircuitMember::Variable(type_) => Some(type_.clone()), CircuitMember::Function(_) => None, @@ -112,7 +101,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessEx // scoping refcell reference let found_member = { - if let Some(member) = circuit.members.borrow().get(&value.name.name) { + if let Some(member) = circuit.members.borrow().get(value.name.name.as_ref()) { if let Some(expected_type) = &expected_type { if let CircuitMember::Variable(type_) = &member { let type_: Type = type_.clone(); @@ -136,10 +125,10 @@ impl<'a> FromAst<'a, leo_ast::CircuitMemberAccessExpression> for CircuitAccessEx } else if circuit.is_input_pseudo_circuit() { // add new member to implicit input if let Some(expected_type) = expected_type.map(PartialType::full).flatten() { - circuit - .members - .borrow_mut() - .insert(value.name.name.clone(), CircuitMember::Variable(expected_type.clone())); + circuit.members.borrow_mut().insert( + value.name.name.to_string(), + CircuitMember::Variable(expected_type.clone()), + ); } else { return Err(AsgConvertError::input_ref_needs_type( &circuit.name.borrow().name, @@ -192,7 +181,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitStaticFunctionAccessExpression> for Circuit )); } - if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(&value.name.name) { + if let Some(CircuitMember::Function(_)) = circuit.members.borrow().get(value.name.name.as_ref()) { // okay } else { return Err(AsgConvertError::unresolved_circuit_member( diff --git a/asg/src/expression/circuit_init.rs b/asg/src/expression/circuit_init.rs index 8c26379072..d14a3e91fb 100644 --- a/asg/src/expression/circuit_init.rs +++ b/asg/src/expression/circuit_init.rs @@ -15,19 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - Circuit, - CircuitMember, - ConstValue, - Expression, - ExpressionNode, - FromAst, - Identifier, - Node, - PartialType, - Scope, - Span, - Type, + AsgConvertError, Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, + PartialType, Scope, Span, Type, }; use indexmap::{IndexMap, IndexSet}; @@ -99,10 +88,10 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<' )); } } - let members: IndexMap<&String, (&Identifier, Option<&leo_ast::Expression>)> = value + let members: IndexMap<&str, (&Identifier, Option<&leo_ast::Expression>)> = value .members .iter() - .map(|x| (&x.identifier.name, (&x.identifier, x.expression.as_ref()))) + .map(|x| (x.identifier.name.as_ref(), (&x.identifier, x.expression.as_ref()))) .collect(); let mut values: Vec<(Identifier, Cell<&'a Expression<'a>>)> = vec![]; @@ -124,7 +113,7 @@ impl<'a> FromAst<'a, leo_ast::CircuitInitExpression> for CircuitInitExpression<' } else { continue; }; - if let Some((identifier, receiver)) = members.get(&name) { + if let Some((identifier, receiver)) = members.get(&**name) { let received = if let Some(receiver) = *receiver { <&Expression<'a>>::from_ast(scope, receiver, Some(type_.partial()))? } else { diff --git a/asg/src/expression/constant.rs b/asg/src/expression/constant.rs index ae2a1fdd13..1310596635 100644 --- a/asg/src/expression/constant.rs +++ b/asg/src/expression/constant.rs @@ -15,18 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - ConstInt, - ConstValue, - Expression, - ExpressionNode, - FromAst, - GroupValue, - Node, - PartialType, - Scope, - Span, - Type, + AsgConvertError, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, GroupValue, Node, PartialType, Scope, + Span, Type, }; use std::cell::Cell; @@ -174,12 +164,12 @@ impl<'a> FromAst<'a, leo_ast::ValueExpression> for Constant<'a> { Some(PartialType::Type(Type::Group)) => Constant { parent: Cell::new(None), span: Some(span.clone()), - value: ConstValue::Group(GroupValue::Single(value.to_string())), + value: ConstValue::Group(GroupValue::Single(value.clone())), }, Some(PartialType::Type(Type::Address)) => Constant { parent: Cell::new(None), span: Some(span.clone()), - value: ConstValue::Address(value.to_string()), + value: ConstValue::Address(value.clone()), }, Some(x) => return Err(AsgConvertError::unexpected_type(&x.to_string(), Some("unknown"), span)), }, @@ -213,10 +203,10 @@ impl<'a> Into for &Constant<'a> { leo_ast::ValueExpression::Address(value.clone(), self.span.clone().unwrap_or_default()) } ConstValue::Boolean(value) => { - leo_ast::ValueExpression::Boolean(value.to_string(), self.span.clone().unwrap_or_default()) + leo_ast::ValueExpression::Boolean(value.to_string().into(), self.span.clone().unwrap_or_default()) } ConstValue::Field(value) => { - leo_ast::ValueExpression::Field(value.to_string(), self.span.clone().unwrap_or_default()) + leo_ast::ValueExpression::Field(value.to_string().into(), self.span.clone().unwrap_or_default()) } ConstValue::Group(value) => leo_ast::ValueExpression::Group(Box::new(match value { GroupValue::Single(single) => { @@ -230,7 +220,7 @@ impl<'a> Into for &Constant<'a> { })), ConstValue::Int(int) => leo_ast::ValueExpression::Integer( int.get_int_type(), - int.raw_value(), + int.raw_value().into(), self.span.clone().unwrap_or_default(), ), ConstValue::Tuple(_) => unimplemented!(), diff --git a/asg/src/expression/tuple_access.rs b/asg/src/expression/tuple_access.rs index 4886ff4aa6..6a9b2839e6 100644 --- a/asg/src/expression/tuple_access.rs +++ b/asg/src/expression/tuple_access.rs @@ -109,7 +109,7 @@ impl<'a> Into for &TupleAccessExpression<'a> { leo_ast::TupleAccessExpression { tuple: Box::new(self.tuple_ref.get().into()), index: leo_ast::PositiveNumber { - value: self.index.to_string(), + value: self.index.to_string().into(), }, span: self.span.clone().unwrap_or_default(), } diff --git a/asg/src/expression/variable_ref.rs b/asg/src/expression/variable_ref.rs index 6a5476b40a..349c93ccd4 100644 --- a/asg/src/expression/variable_ref.rs +++ b/asg/src/expression/variable_ref.rs @@ -15,20 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - ConstValue, - Constant, - DefinitionStatement, - Expression, - ExpressionNode, - FromAst, - Node, - PartialType, - Scope, - Span, - Statement, - Type, - Variable, + AsgConvertError, ConstValue, Constant, DefinitionStatement, Expression, ExpressionNode, FromAst, Node, PartialType, + Scope, Span, Statement, Type, Variable, }; use std::cell::Cell; @@ -136,7 +124,7 @@ impl<'a> FromAst<'a, leo_ast::Identifier> for &'a Expression<'a> { value: &leo_ast::Identifier, expected_type: Option>, ) -> Result<&'a Expression<'a>, AsgConvertError> { - let variable = if value.name == "input" { + let variable = if value.name.as_ref() == "input" { if let Some(function) = scope.resolve_current_function() { if !function.has_input { return Err(AsgConvertError::unresolved_reference(&value.name, &value.span)); diff --git a/asg/src/input.rs b/asg/src/input.rs index 7f186d97e0..b22ee2f8b9 100644 --- a/asg/src/input.rs +++ b/asg/src/input.rs @@ -40,7 +40,7 @@ impl<'a> Input<'a> { fn make_header(scope: &'a Scope<'a>, name: &str) -> &'a Circuit<'a> { scope.context.alloc_circuit(Circuit { id: scope.context.get_id(), - name: RefCell::new(Identifier::new(name.to_string())), + name: RefCell::new(Identifier::new(name.into())), members: RefCell::new(IndexMap::new()), core_mapping: RefCell::new(None), scope, @@ -69,7 +69,7 @@ impl<'a> Input<'a> { let container_circuit = input_scope.context.alloc_circuit(Circuit { id: scope.context.get_id(), - name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.to_string())), + name: RefCell::new(Identifier::new(CONTAINER_PSEUDO_CIRCUIT.into())), members: RefCell::new(container_members), core_mapping: RefCell::new(None), scope: input_scope, @@ -84,7 +84,7 @@ impl<'a> Input<'a> { container_circuit, container: input_scope.context.alloc_variable(RefCell::new(crate::InnerVariable { id: scope.context.get_id(), - name: Identifier::new("input".to_string()), + name: Identifier::new("input".into()), type_: Type::Circuit(container_circuit), mutable: false, const_: false, diff --git a/asg/src/node.rs b/asg/src/node.rs index 58b4b7709e..5b1b026802 100644 --- a/asg/src/node.rs +++ b/asg/src/node.rs @@ -15,16 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - AsgContextInner, - AsgConvertError, - Circuit, - Expression, - Function, - PartialType, - Scope, - Span, - Statement, - Variable, + AsgContextInner, AsgConvertError, Circuit, Expression, Function, PartialType, Scope, Span, Statement, Variable, }; /// A node in the abstract semantic graph. diff --git a/asg/src/program/circuit.rs b/asg/src/program/circuit.rs index 6ca447234e..18858840d9 100644 --- a/asg/src/program/circuit.rs +++ b/asg/src/program/circuit.rs @@ -69,7 +69,7 @@ impl<'a> Circuit<'a> { let mut members = circuit.members.borrow_mut(); for member in value.members.iter() { if let leo_ast::CircuitMember::CircuitVariable(name, type_) = member { - if members.contains_key(&name.name) { + if members.contains_key(name.name.as_ref()) { return Err(AsgConvertError::redefined_circuit_member( &value.circuit_name.name, &name.name, @@ -77,7 +77,7 @@ impl<'a> Circuit<'a> { )); } members.insert( - name.name.clone(), + name.name.to_string(), CircuitMember::Variable(new_scope.resolve_ast_type(type_)?), ); } @@ -93,13 +93,13 @@ impl<'a> Circuit<'a> { let new_scope = scope.make_subscope(); let circuits = scope.circuits.borrow(); - let circuit = circuits.get(&value.circuit_name.name).unwrap(); + let circuit = circuits.get(value.circuit_name.name.as_ref()).unwrap(); new_scope.circuit_self.replace(Some(circuit)); let mut members = circuit.members.borrow_mut(); for member in value.members.iter() { if let leo_ast::CircuitMember::CircuitFunction(function) = member { - if members.contains_key(&function.identifier.name) { + if members.contains_key(function.identifier.name.as_ref()) { return Err(AsgConvertError::redefined_circuit_member( &value.circuit_name.name, &function.identifier.name, @@ -111,7 +111,7 @@ impl<'a> Circuit<'a> { if asg_function.is_test() { return Err(AsgConvertError::circuit_test_function(&function.identifier.span)); } - members.insert(function.identifier.name.clone(), CircuitMember::Function(asg_function)); + members.insert(function.identifier.name.to_string(), CircuitMember::Function(asg_function)); } } @@ -126,7 +126,7 @@ impl<'a> Circuit<'a> { let asg_function = match *self .members .borrow() - .get(&function.identifier.name) + .get(function.identifier.name.as_ref()) .expect("missing header for defined circuit function") { CircuitMember::Function(f) => f, @@ -148,7 +148,7 @@ impl<'a> Into for &Circuit<'a> { .iter() .map(|(name, member)| match &member { CircuitMember::Variable(type_) => { - leo_ast::CircuitMember::CircuitVariable(Identifier::new(name.clone()), type_.into()) + leo_ast::CircuitMember::CircuitVariable(Identifier::new((&**name).into()), type_.into()) } CircuitMember::Function(func) => leo_ast::CircuitMember::CircuitFunction((*func).into()), }) diff --git a/asg/src/program/function.rs b/asg/src/program/function.rs index 89f5fe71e9..436570ab26 100644 --- a/asg/src/program/function.rs +++ b/asg/src/program/function.rs @@ -15,18 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - BlockStatement, - Circuit, - FromAst, - Identifier, - MonoidalDirector, - ReturnPathReducer, - Scope, - Span, - Statement, - Type, - Variable, + AsgConvertError, BlockStatement, Circuit, FromAst, Identifier, MonoidalDirector, ReturnPathReducer, Scope, Span, + Statement, Type, Variable, }; use indexmap::IndexMap; pub use leo_ast::Annotation; @@ -113,7 +103,7 @@ impl<'a> Function<'a> { references: vec![], assignments: vec![], })); - arguments.insert(identifier.name.clone(), Cell::new(&*variable)); + arguments.insert(identifier.name.to_string(), Cell::new(&*variable)); } } } @@ -144,7 +134,7 @@ impl<'a> Function<'a> { let circuit = self.circuit.get(); let self_variable = self.scope.context.alloc_variable(RefCell::new(crate::InnerVariable { id: self.scope.context.get_id(), - name: Identifier::new("self".to_string()), + name: Identifier::new("self".into()), type_: Type::Circuit(circuit.as_ref().unwrap()), mutable: self.qualifier == FunctionQualifier::MutSelfRef, const_: false, @@ -186,7 +176,7 @@ impl<'a> Function<'a> { } pub fn is_test(&self) -> bool { - self.annotations.iter().any(|x| x.name.name == "test") + self.annotations.iter().any(|x| x.name.name.as_ref() == "test") } } diff --git a/asg/src/program/mod.rs b/asg/src/program/mod.rs index 56f93c1d40..c38ab404e5 100644 --- a/asg/src/program/mod.rs +++ b/asg/src/program/mod.rs @@ -75,11 +75,11 @@ fn resolve_import_package( ) { match package_or_packages { PackageOrPackages::Package(package) => { - package_segments.push(package.name.name.clone()); + package_segments.push(package.name.name.to_string()); resolve_import_package_access(output, package_segments, &package.access); } PackageOrPackages::Packages(packages) => { - package_segments.push(packages.name.name.clone()); + package_segments.push(packages.name.name.to_string()); for access in packages.accesses.clone() { resolve_import_package_access(output, package_segments.clone(), &access); } @@ -106,14 +106,14 @@ fn resolve_import_package_access( PackageAccess::Symbol(symbol) => { let span = symbol.symbol.span.clone(); let symbol = if let Some(alias) = symbol.alias.as_ref() { - ImportSymbol::Alias(symbol.symbol.name.clone(), alias.name.clone()) + ImportSymbol::Alias(symbol.symbol.name.to_string(), alias.name.to_string()) } else { - ImportSymbol::Direct(symbol.symbol.name.clone()) + ImportSymbol::Direct(symbol.symbol.name.to_string()) }; output.push((package_segments, symbol, span)); } PackageAccess::Multiple(packages) => { - package_segments.push(packages.name.name.clone()); + package_segments.push(packages.name.name.to_string()); for subaccess in packages.accesses.iter() { resolve_import_package_access(output, package_segments.clone(), &subaccess); } @@ -240,7 +240,7 @@ impl<'a> Program<'a> { assert_eq!(name.name, circuit.circuit_name.name); let asg_circuit = Circuit::init(scope, circuit)?; - scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit); + scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit); } // Second pass for circuit members. @@ -248,35 +248,35 @@ impl<'a> Program<'a> { assert_eq!(name.name, circuit.circuit_name.name); let asg_circuit = Circuit::init_member(scope, circuit)?; - scope.circuits.borrow_mut().insert(name.name.clone(), asg_circuit); + scope.circuits.borrow_mut().insert(name.name.to_string(), asg_circuit); } for (name, function) in program.functions.iter() { assert_eq!(name.name, function.identifier.name); let function = Function::init(scope, function)?; - scope.functions.borrow_mut().insert(name.name.clone(), function); + scope.functions.borrow_mut().insert(name.name.to_string(), function); } // Load concrete definitions. let mut functions = IndexMap::new(); for (name, function) in program.functions.iter() { assert_eq!(name.name, function.identifier.name); - let asg_function = *scope.functions.borrow().get(&name.name).unwrap(); + let asg_function = *scope.functions.borrow().get(name.name.as_ref()).unwrap(); asg_function.fill_from_ast(function)?; - functions.insert(name.name.clone(), asg_function); + functions.insert(name.name.to_string(), asg_function); } let mut circuits = IndexMap::new(); for (name, circuit) in program.circuits.iter() { assert_eq!(name.name, circuit.circuit_name.name); - let asg_circuit = *scope.circuits.borrow().get(&name.name).unwrap(); + let asg_circuit = *scope.circuits.borrow().get(name.name.as_ref()).unwrap(); asg_circuit.fill_from_ast(circuit)?; - circuits.insert(name.name.clone(), asg_circuit); + circuits.insert(name.name.to_string(), asg_circuit); } Ok(Program { @@ -338,7 +338,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program { for (_, program) in all_programs.into_iter() { for (name, circuit) in program.circuits.iter() { let identifier = format!("{}{}", identifiers.next().unwrap(), name); - circuit.name.borrow_mut().name = identifier.clone(); + circuit.name.borrow_mut().name = identifier.clone().into(); all_circuits.insert(identifier, *circuit); } for (name, function) in program.functions.iter() { @@ -347,7 +347,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program { } else { format!("{}{}", identifiers.next().unwrap(), name) }; - function.name.borrow_mut().name = identifier.clone(); + function.name.borrow_mut().name = identifier.clone().into(); all_functions.insert(identifier, *function); } } @@ -358,7 +358,7 @@ pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program { .iter() .map(|(module, _)| leo_ast::ImportStatement { package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package { - name: Identifier::new(module.clone()), + name: Identifier::new(module.clone().into()), access: leo_ast::PackageAccess::Star(Span::default()), span: Default::default(), }), diff --git a/asg/src/scope.rs b/asg/src/scope.rs index 2a8ac9d093..fac0d8813c 100644 --- a/asg/src/scope.rs +++ b/asg/src/scope.rs @@ -194,7 +194,7 @@ impl<'a> Scope<'a> { .map(|x| self.resolve_ast_type(x)) .collect::, AsgConvertError>>()?, ), - Circuit(name) if name.name == "Self" => Type::Circuit( + Circuit(name) if name.name.as_ref() == "Self" => Type::Circuit( self.resolve_circuit_self() .ok_or_else(|| AsgConvertError::unresolved_circuit(&name.name, &name.span))?, ), diff --git a/asg/src/statement/assign.rs b/asg/src/statement/assign.rs index 110105a2bf..df9b525029 100644 --- a/asg/src/statement/assign.rs +++ b/asg/src/statement/assign.rs @@ -15,22 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - CircuitMember, - ConstInt, - ConstValue, - Expression, - ExpressionNode, - FromAst, - Identifier, - IntegerType, - Node, - PartialType, - Scope, - Span, - Statement, - Type, - Variable, + AsgConvertError, CircuitMember, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, Identifier, IntegerType, + Node, PartialType, Scope, Span, Statement, Type, Variable, }; pub use leo_ast::AssignOperation; use leo_ast::AssigneeAccess as AstAssigneeAccess; @@ -69,7 +55,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> { ) -> Result { let (name, span) = (&statement.assignee.identifier.name, &statement.assignee.identifier.span); - let variable = if name == "input" { + let variable = if name.as_ref() == "input" { if let Some(function) = scope.resolve_current_function() { if !function.has_input { return Err(AsgConvertError::unresolved_reference(name, &span)); @@ -188,7 +174,7 @@ impl<'a> FromAst<'a, leo_ast::AssignStatement> for &'a Statement<'a> { let circuit = circuit; let members = circuit.members.borrow(); - let member = members.get(&name.name).ok_or_else(|| { + let member = members.get(name.name.as_ref()).ok_or_else(|| { AsgConvertError::unresolved_circuit_member( &circuit.name.borrow().name, &name.name, @@ -251,7 +237,7 @@ impl<'a> Into for &AssignStatement<'a> { AssignAccess::ArrayIndex(index) => AstAssigneeAccess::ArrayIndex(index.get().into()), AssignAccess::Tuple(index) => AstAssigneeAccess::Tuple( leo_ast::PositiveNumber { - value: index.to_string(), + value: index.to_string().into(), }, self.span.clone().unwrap_or_default(), ), diff --git a/asg/src/statement/definition.rs b/asg/src/statement/definition.rs index fb9b7be2ee..a835483cbe 100644 --- a/asg/src/statement/definition.rs +++ b/asg/src/statement/definition.rs @@ -15,18 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, - Expression, - ExpressionNode, - FromAst, - InnerVariable, - Node, - PartialType, - Scope, - Span, - Statement, - Type, - Variable, + AsgConvertError, Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Span, Statement, + Type, Variable, }; use std::cell::{Cell, RefCell}; @@ -106,7 +96,7 @@ impl<'a> FromAst<'a, leo_ast::DefinitionStatement> for &'a Statement<'a> { scope .variables .borrow_mut() - .insert(variable.borrow().name.name.clone(), *variable); + .insert(variable.borrow().name.name.to_string(), *variable); } let statement = scope diff --git a/asg/src/statement/iteration.rs b/asg/src/statement/iteration.rs index d5908d24da..713d4d0ea9 100644 --- a/asg/src/statement/iteration.rs +++ b/asg/src/statement/iteration.rs @@ -17,16 +17,7 @@ use leo_ast::IntegerType; use crate::{ - AsgConvertError, - Expression, - ExpressionNode, - FromAst, - InnerVariable, - Node, - PartialType, - Scope, - Span, - Statement, + AsgConvertError, Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Span, Statement, Variable, }; @@ -85,7 +76,7 @@ impl<'a> FromAst<'a, leo_ast::IterationStatement> for &'a Statement<'a> { scope .variables .borrow_mut() - .insert(statement.variable.name.clone(), variable); + .insert(statement.variable.name.to_string(), variable); let statement = scope.context.alloc_statement(Statement::Iteration(IterationStatement { parent: Cell::new(None), diff --git a/asg/src/type_.rs b/asg/src/type_.rs index 8421d436fc..b578f0d9b8 100644 --- a/asg/src/type_.rs +++ b/asg/src/type_.rs @@ -204,7 +204,9 @@ impl<'a> Into for &Type<'a> { Integer(int_type) => leo_ast::Type::IntegerType(int_type.clone()), Array(type_, len) => leo_ast::Type::Array( Box::new(type_.as_ref().into()), - leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber { value: len.to_string() }]), + leo_ast::ArrayDimensions(vec![leo_ast::PositiveNumber { + value: len.to_string().into(), + }]), ), Tuple(subtypes) => leo_ast::Type::Tuple(subtypes.iter().map(Into::into).collect()), Circuit(circuit) => leo_ast::Type::Circuit(circuit.name.borrow().clone()), diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 28a2b8e277..70193122ef 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -41,6 +41,9 @@ version = "1.0" [dependencies.thiserror] version = "1.0" +[dependencies.tendril] +version = "0.4" + [dev-dependencies.criterion] version = "0.3" diff --git a/ast/src/annotation.rs b/ast/src/annotation.rs index aebfd3b083..5720e55a4b 100644 --- a/ast/src/annotation.rs +++ b/ast/src/annotation.rs @@ -17,10 +17,12 @@ use crate::{Identifier, Span}; use serde::{Deserialize, Serialize}; +use tendril::StrTendril; #[derive(Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Annotation { pub span: Span, pub name: Identifier, - pub arguments: Vec, + #[serde(with = "crate::common::vec_tendril_json")] + pub arguments: Vec, } diff --git a/ast/src/common/array_dimensions.rs b/ast/src/common/array_dimensions.rs index bdcd6b3db9..b0079c902f 100644 --- a/ast/src/common/array_dimensions.rs +++ b/ast/src/common/array_dimensions.rs @@ -32,7 +32,7 @@ impl ArrayDimensions { /// pub fn push_usize(&mut self, number: usize) { let positive_number = PositiveNumber { - value: number.to_string(), + value: number.to_string().into(), }; self.0.push(positive_number) diff --git a/ast/src/common/identifier.rs b/ast/src/common/identifier.rs index 46ab97e819..6728212c77 100644 --- a/ast/src/common/identifier.rs +++ b/ast/src/common/identifier.rs @@ -16,17 +16,14 @@ use crate::Span; use leo_input::common::Identifier as InputIdentifier; +use tendril::StrTendril; use crate::Node; use serde::{ de::{ - Visitor, - {self}, + Visitor, {self}, }, - Deserialize, - Deserializer, - Serialize, - Serializer, + Deserialize, Deserializer, Serialize, Serializer, }; use std::{ collections::BTreeMap, @@ -41,7 +38,7 @@ use std::{ /// to reflect the new struct instantiation. #[derive(Clone)] pub struct Identifier { - pub name: String, + pub name: StrTendril, pub span: Span, } @@ -56,7 +53,7 @@ impl Node for Identifier { } impl Identifier { - pub fn new(name: String) -> Self { + pub fn new(name: StrTendril) -> Self { Self { name, span: Span::default(), @@ -65,24 +62,16 @@ impl Identifier { pub fn new_with_span(name: &str, span: Span) -> Self { Self { - name: name.to_owned(), + name: name.into(), span, } } - - pub fn is_self_type(&self) -> bool { - self.name == "Self" - } - - pub fn is_self(&self) -> bool { - self.is_self_type() || self.name == "self" - } } impl<'ast> From> for Identifier { fn from(identifier: InputIdentifier<'ast>) -> Self { Self { - name: identifier.value, + name: identifier.value.into(), span: Span::from(identifier.span), } } @@ -123,7 +112,7 @@ impl Serialize for Identifier { // Load the struct elements into a BTreeMap (to preserve serialized ordering of keys). let mut key: BTreeMap = BTreeMap::new(); - key.insert("name".to_string(), self.name.clone()); + key.insert("name".to_string(), self.name.to_string()); key.insert("span".to_string(), to_json_string(&self.span)?); // Convert the serialized object into a string for use as a key. @@ -164,7 +153,10 @@ impl<'de> Deserialize<'de> for Identifier { None => return Err(E::custom("missing 'span' in serialized Identifier struct")), }; - Ok(Identifier { name, span }) + Ok(Identifier { + name: name.into(), + span, + }) } } diff --git a/ast/src/common/mod.rs b/ast/src/common/mod.rs index a5f8c8f9c4..e7bd108cd2 100644 --- a/ast/src/common/mod.rs +++ b/ast/src/common/mod.rs @@ -40,3 +40,7 @@ pub use span::*; pub mod spread_or_expression; pub use spread_or_expression::*; + +pub mod tendril_json; + +pub mod vec_tendril_json; diff --git a/ast/src/common/positive_number.rs b/ast/src/common/positive_number.rs index 80fda5d71e..f674463607 100644 --- a/ast/src/common/positive_number.rs +++ b/ast/src/common/positive_number.rs @@ -18,11 +18,13 @@ use leo_input::values::PositiveNumber as InputPositiveNumber; use serde::{Deserialize, Serialize}; use std::fmt; +use tendril::StrTendril; /// A number string guaranteed to be positive by the pest grammar. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)] pub struct PositiveNumber { - pub value: String, + #[serde(with = "crate::common::tendril_json")] + pub value: StrTendril, } impl PositiveNumber { @@ -30,14 +32,16 @@ impl PositiveNumber { /// Returns `true` if this number is zero. /// pub fn is_zero(&self) -> bool { - self.value.eq("0") + self.value.as_ref().eq("0") } } /// Create a new [`PositiveNumber`] from an [`InputPositiveNumber`] in a Leo input file. impl<'ast> From> for PositiveNumber { fn from(array: InputPositiveNumber<'ast>) -> Self { - Self { value: array.value } + Self { + value: array.value.into(), + } } } diff --git a/ast/src/common/span.rs b/ast/src/common/span.rs index 1f672f9889..830437a39b 100644 --- a/ast/src/common/span.rs +++ b/ast/src/common/span.rs @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{fmt, rc::Rc}; +use std::{fmt, sync::Arc}; use serde::{Deserialize, Serialize}; +use tendril::StrTendril; #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct Span { @@ -24,7 +25,9 @@ pub struct Span { pub line_stop: usize, pub col_start: usize, pub col_stop: usize, - pub path: Rc, + pub path: Arc, + #[serde(with = "crate::common::tendril_json")] + pub content: StrTendril, } impl fmt::Display for Span { @@ -51,7 +54,8 @@ impl<'ast> From> for Span { line_stop: end.0, col_start: start.1, col_stop: end.1, - path: Rc::new(String::new()), + path: Arc::new(String::new()), + content: span.as_str().into(), } } } @@ -76,22 +80,40 @@ impl std::ops::Add for Span { col_start: self.col_start.min(other.col_start), col_stop: self.col_stop.max(other.col_stop), path: self.path, - } - } else if self.line_start < other.line_stop { - Span { - line_start: self.line_start, - line_stop: other.line_stop, - col_start: self.col_start, - col_stop: other.col_stop, - path: self.path, + content: self.content, } } else { - Span { - line_start: other.line_start, - line_stop: self.line_stop, - col_start: other.col_start, - col_stop: self.col_stop, - path: self.path, + let mut new_content = vec![]; + let self_lines = self.content.lines().collect::>(); + let other_lines = other.content.lines().collect::>(); + for line in self.line_start.min(other.line_start)..self.line_stop.max(other.line_stop) + 1 { + if line >= self.line_start && line <= self.line_stop { + new_content.push(self_lines.get(line - self.line_start).copied().unwrap_or_default()); + } else if line >= other.line_start && line <= other.line_stop { + new_content.push(other_lines.get(line - other.line_start).copied().unwrap_or_default()); + } else if new_content.last().map(|x| *x != "...").unwrap_or(true) { + new_content.push("..."); + } + } + let new_content = new_content.join("\n").into(); + if self.line_start < other.line_stop { + Span { + line_start: self.line_start, + line_stop: other.line_stop, + col_start: self.col_start, + col_stop: other.col_stop, + path: self.path, + content: new_content, + } + } else { + Span { + line_start: other.line_start, + line_stop: self.line_stop, + col_start: other.col_start, + col_stop: self.col_stop, + path: self.path, + content: new_content, + } } } } diff --git a/ast/src/common/tendril_json.rs b/ast/src/common/tendril_json.rs new file mode 100644 index 0000000000..35c9b45759 --- /dev/null +++ b/ast/src/common/tendril_json.rs @@ -0,0 +1,26 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use serde::{Deserialize, Deserializer, Serializer}; +use tendril::StrTendril; + +pub fn serialize(tendril: &StrTendril, serializer: S) -> Result { + serializer.serialize_str(&tendril[..]) +} + +pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { + Ok(String::deserialize(deserializer)?.into()) +} diff --git a/ast/src/common/vec_tendril_json.rs b/ast/src/common/vec_tendril_json.rs new file mode 100644 index 0000000000..27d7d02667 --- /dev/null +++ b/ast/src/common/vec_tendril_json.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use tendril::StrTendril; + +pub fn serialize(tendril: &Vec, serializer: S) -> Result { + tendril + .iter() + .map(|x| x.as_ref()) + .collect::>() + .serialize(serializer) +} + +pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { + Ok(Vec::::deserialize(deserializer)? + .into_iter() + .map(|x| x.into()) + .collect()) +} diff --git a/ast/src/errors/error.rs b/ast/src/errors/error.rs index 1f029866aa..ef6f69337f 100644 --- a/ast/src/errors/error.rs +++ b/ast/src/errors/error.rs @@ -16,7 +16,7 @@ use crate::{LeoError, Span}; -use std::fmt; +use std::{fmt, sync::Arc}; pub const INDENT: &str = " "; @@ -29,60 +29,30 @@ pub const INDENT: &str = " "; /// = undefined value `x` #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct FormattedError { - /// File path where error occurred - pub path: Option, - /// Line start number pub line_start: usize, - /// Line end number pub line_stop: usize, - /// Starting column - pub start: usize, - /// Ending column - pub end: usize, - /// Text of errored lines - pub text: Option>, - /// Error explanation + pub col_start: usize, + pub col_stop: usize, + pub path: Arc, + pub content: String, pub message: String, } impl FormattedError { pub fn new_from_span(message: String, span: &Span) -> Self { Self { - path: None, line_start: span.line_start, line_stop: span.line_stop, - start: span.col_start, - end: span.col_stop, - text: None, + col_start: span.col_start, + col_stop: span.col_stop, + path: span.path.clone(), + content: span.content.to_string(), message, } } } -impl LeoError for FormattedError { - fn set_path(&mut self, path: &str, content: &[String]) { - self.path = Some(path.to_string()); - if self.line_stop - 1 > content.len() { - self.text = Some(vec!["corrupt file".to_string()]); - return; - } - assert!(self.line_stop >= self.line_start); - // if self.line_stop == self.line_start { - // self.text = Some(vec![content[self.line_start - 1][self.start - 1..self.end - 1].to_string()]); - // } else { - self.text = Some( - content[self.line_start - 1..self.line_stop] - .iter() - .map(|x| x.to_string()) - .collect(), - ); - // } - } - - fn get_path(&self) -> Option<&str> { - self.path.as_deref() - } -} +impl LeoError for FormattedError {} fn underline(mut start: usize, mut end: usize) -> String { if start > end { @@ -105,29 +75,26 @@ fn underline(mut start: usize, mut end: usize) -> String { impl fmt::Display for FormattedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let path = self.path.as_ref().map(|path| format!("{}:", path)).unwrap_or_default(); - let underline = underline(self.start - 1, self.end - 1); + let underline = underline(self.col_start - 1, self.col_stop - 1); write!( f, - "{indent }--> {path} {line_start}:{start}\n\ + "{indent }--> {path}: {line_start}:{start}\n\ {indent } |\n", indent = INDENT, - path = path, + path = &*self.path, line_start = self.line_start, - start = self.start, + start = self.col_start, )?; - if let Some(lines) = &self.text { - for (line_no, line) in lines.iter().enumerate() { - writeln!( - f, - "{line_no:width$} | {text}", - width = INDENT.len(), - line_no = self.line_start + line_no, - text = line, - )?; - } + for (line_no, line) in self.content.lines().enumerate() { + writeln!( + f, + "{line_no:width$} | {text}", + width = INDENT.len(), + line_no = self.line_start + line_no, + text = line, + )?; } write!( @@ -151,12 +118,12 @@ impl std::error::Error for FormattedError { #[test] fn test_error() { let err = FormattedError { - path: Some("file.leo".to_string()), + path: std::sync::Arc::new("file.leo".to_string()), line_start: 2, line_stop: 2, - start: 8, - end: 9, - text: Some(vec!["let a = x;".to_string()]), + col_start: 8, + col_stop: 9, + content: "let a = x;".into(), message: "undefined value `x`".to_string(), }; diff --git a/ast/src/errors/mod.rs b/ast/src/errors/mod.rs index 1e8b06996f..c998e0c485 100644 --- a/ast/src/errors/mod.rs +++ b/ast/src/errors/mod.rs @@ -17,8 +17,4 @@ pub mod error; pub use error::*; -pub trait LeoError { - fn get_path(&self) -> Option<&str>; - - fn set_path(&mut self, path: &str, contents: &[String]); -} +pub trait LeoError {} diff --git a/ast/src/expression/mod.rs b/ast/src/expression/mod.rs index 701efc50bc..2d2389d0ac 100644 --- a/ast/src/expression/mod.rs +++ b/ast/src/expression/mod.rs @@ -15,13 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - ArrayDimensions, - CircuitImpliedVariableDefinition, - GroupValue, - Identifier, - IntegerType, - PositiveNumber, - Span, + ArrayDimensions, CircuitImpliedVariableDefinition, GroupValue, Identifier, IntegerType, PositiveNumber, Span, SpreadOrExpression, }; diff --git a/ast/src/expression/value.rs b/ast/src/expression/value.rs index 572fd24aef..9b3ceda943 100644 --- a/ast/src/expression/value.rs +++ b/ast/src/expression/value.rs @@ -14,18 +14,24 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use tendril::StrTendril; + use super::*; use crate::GroupTuple; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum ValueExpression { // todo: deserialize values here - Address(String, Span), - Boolean(String, Span), - Field(String, Span), + Address(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), + Boolean(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), + Field(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), Group(Box), - Implicit(String, Span), - Integer(IntegerType, String, Span), + Implicit(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), + Integer( + IntegerType, + #[serde(with = "crate::common::tendril_json")] StrTendril, + Span, + ), } impl fmt::Display for ValueExpression { diff --git a/ast/src/groups/group_coordinate.rs b/ast/src/groups/group_coordinate.rs index 5f64c476dc..b8d05ee786 100644 --- a/ast/src/groups/group_coordinate.rs +++ b/ast/src/groups/group_coordinate.rs @@ -16,19 +16,17 @@ use crate::common::span::Span; use leo_input::values::{ - GroupCoordinate as InputGroupCoordinate, - Inferred as InputInferred, - NumberValue as InputNumberValue, - SignHigh as InputSignHigh, - SignLow as InputSignLow, + GroupCoordinate as InputGroupCoordinate, Inferred as InputInferred, NumberValue as InputNumberValue, + SignHigh as InputSignHigh, SignLow as InputSignLow, }; use serde::{Deserialize, Serialize}; use std::fmt; +use tendril::StrTendril; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum GroupCoordinate { - Number(String, Span), + Number(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), SignHigh, SignLow, Inferred, @@ -61,7 +59,7 @@ impl<'ast> From> for GroupCoordinate { let value = number.to_string(); let span = Span::from(number.span().clone()); - GroupCoordinate::Number(value, span) + GroupCoordinate::Number(value.into(), span) } } diff --git a/ast/src/groups/group_value.rs b/ast/src/groups/group_value.rs index e36aba3659..e3bff066dc 100644 --- a/ast/src/groups/group_value.rs +++ b/ast/src/groups/group_value.rs @@ -16,17 +16,16 @@ use crate::{common::span::Span, groups::GroupCoordinate}; use leo_input::values::{ - GroupRepresentation as InputGroupRepresentation, - GroupTuple as InputGroupTuple, - GroupValue as InputGroupValue, + GroupRepresentation as InputGroupRepresentation, GroupTuple as InputGroupTuple, GroupValue as InputGroupValue, }; use serde::{Deserialize, Serialize}; use std::fmt; +use tendril::StrTendril; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum GroupValue { - Single(String, Span), + Single(#[serde(with = "crate::common::tendril_json")] StrTendril, Span), Tuple(GroupTuple), } @@ -51,7 +50,7 @@ impl<'ast> From> for GroupValue { let span = Span::from(ast_group.span); match ast_group.value { - InputGroupRepresentation::Single(number) => GroupValue::Single(number.to_string(), span), + InputGroupRepresentation::Single(number) => GroupValue::Single(number.to_string().into(), span), InputGroupRepresentation::Tuple(tuple) => GroupValue::Tuple(GroupTuple::from(tuple)), } } diff --git a/ast/src/imports/import_symbol.rs b/ast/src/imports/import_symbol.rs index cc7a038dad..4d82b898d9 100644 --- a/ast/src/imports/import_symbol.rs +++ b/ast/src/imports/import_symbol.rs @@ -51,7 +51,7 @@ impl ImportSymbol { pub fn star(span: &Span) -> Self { Self { symbol: Identifier { - name: "*".to_string(), + name: "*".into(), span: span.clone(), }, alias: None, @@ -60,6 +60,6 @@ impl ImportSymbol { } pub fn is_star(&self) -> bool { - self.symbol.name.eq("*") + self.symbol.name.as_ref().eq("*") } } diff --git a/ast/src/input/input.rs b/ast/src/input/input.rs index c37bb4b4f9..d475489d12 100644 --- a/ast/src/input/input.rs +++ b/ast/src/input/input.rs @@ -96,13 +96,13 @@ impl Input { /// Returns the main function input value with the given `name`. #[allow(clippy::ptr_arg)] - pub fn get(&self, name: &String) -> Option> { + pub fn get(&self, name: &str) -> Option> { self.program_input.get(name) } /// Returns the constant input value with the given `name`. #[allow(clippy::ptr_arg)] - pub fn get_constant(&self, name: &String) -> Option> { + pub fn get_constant(&self, name: &str) -> Option> { self.program_input.get_constant(name) } diff --git a/ast/src/input/program_input/program_input.rs b/ast/src/input/program_input/program_input.rs index a2c99f2570..6644b48fef 100644 --- a/ast/src/input/program_input/program_input.rs +++ b/ast/src/input/program_input/program_input.rs @@ -74,12 +74,12 @@ impl ProgramInput { /// Returns the main function input value with the given `name` #[allow(clippy::ptr_arg)] - pub fn get(&self, name: &String) -> Option> { + pub fn get(&self, name: &str) -> Option> { self.main.get(name) } #[allow(clippy::ptr_arg)] - pub fn get_constant(&self, name: &String) -> Option> { + pub fn get_constant(&self, name: &str) -> Option> { self.constants.get(name) } diff --git a/ast/src/input/program_state/public_state/public_state.rs b/ast/src/input/program_state/public_state/public_state.rs index 995aa06759..7de8b04691 100644 --- a/ast/src/input/program_state/public_state/public_state.rs +++ b/ast/src/input/program_state/public_state/public_state.rs @@ -40,7 +40,11 @@ impl PublicState { } pub fn len(&self) -> usize { - if self.state.is_present() { 1usize } else { 0usize } + if self.state.is_present() { + 1usize + } else { + 0usize + } } /// Parse all input variables included in a file and store them in `self`. diff --git a/ast/src/reducer/canonicalization.rs b/ast/src/reducer/canonicalization.rs index e9be54f691..32c50057af 100644 --- a/ast/src/reducer/canonicalization.rs +++ b/ast/src/reducer/canonicalization.rs @@ -171,7 +171,7 @@ impl Canonicalizer { Expression::CircuitInit(circuit_init) => { let mut name = circuit_init.name.clone(); - if name.name == *"Self" { + if name.name.as_ref() == "Self" { name = self.circuit_name.as_ref().unwrap().clone(); } diff --git a/ast/src/statements/console/formatted_string.rs b/ast/src/statements/console/formatted_string.rs index e5e653e745..542e61ef4a 100644 --- a/ast/src/statements/console/formatted_string.rs +++ b/ast/src/statements/console/formatted_string.rs @@ -18,10 +18,11 @@ use crate::{Expression, Node, Span}; use serde::{Deserialize, Serialize}; use std::fmt; +use tendril::StrTendril; #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] pub enum FormattedStringPart { - Const(String), + Const(#[serde(with = "crate::common::tendril_json")] StrTendril), Container, } diff --git a/ast/src/types/integer_type.rs b/ast/src/types/integer_type.rs index e2f3cab5bc..a7768a3512 100644 --- a/ast/src/types/integer_type.rs +++ b/ast/src/types/integer_type.rs @@ -15,8 +15,7 @@ // along with the Leo library. If not, see . use leo_input::types::{ - IntegerType as InputIntegerType, - SignedIntegerType as InputSignedIntegerType, + IntegerType as InputIntegerType, SignedIntegerType as InputSignedIntegerType, UnsignedIntegerType as InputUnsignedIntegerType, }; diff --git a/ast/src/types/type_.rs b/ast/src/types/type_.rs index f919ce8df2..9d6f6fd20e 100644 --- a/ast/src/types/type_.rs +++ b/ast/src/types/type_.rs @@ -16,10 +16,7 @@ use crate::{ArrayDimensions, Identifier, IntegerType}; use leo_input::types::{ - ArrayType as InputArrayType, - DataType as InputDataType, - TupleType as InputTupleType, - Type as InputType, + ArrayType as InputArrayType, DataType as InputDataType, TupleType as InputTupleType, Type as InputType, }; use serde::{Deserialize, Serialize}; diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 42863ab92f..3088cc309c 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -19,15 +19,11 @@ use crate::{ constraints::{generate_constraints, generate_test_constraints}, errors::CompilerError, - CompilerOptions, - GroupType, - OutputBytes, - OutputFile, + CompilerOptions, GroupType, OutputBytes, OutputFile, }; -use indexmap::IndexMap; pub use leo_asg::{new_context, AsgContext as Context, AsgContext}; use leo_asg::{Asg, AsgPass, FormattedError, Program as AsgProgram}; -use leo_ast::{Input, LeoError, MainInput, Program as AstProgram}; +use leo_ast::{Input, MainInput, Program as AstProgram}; use leo_input::LeoInputParser; use leo_package::inputs::InputPairs; use leo_parser::parse_ast; @@ -39,11 +35,9 @@ use snarkvm_r1cs::{ConstraintSynthesizer, ConstraintSystem, SynthesisError}; use sha2::{Digest, Sha256}; use std::{ - cell::RefCell, fs, marker::PhantomData, path::{Path, PathBuf}, - rc::Rc, }; thread_local! { @@ -68,7 +62,6 @@ pub struct Compiler<'a, F: PrimeField, G: GroupType> { program_input: Input, context: AsgContext<'a>, asg: Option>, - file_contents: RefCell>>>, options: CompilerOptions, _engine: PhantomData, _group: PhantomData, @@ -93,7 +86,6 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { asg: None, context, options: CompilerOptions::default(), - file_contents: RefCell::new(IndexMap::new()), _engine: PhantomData, _group: PhantomData, } @@ -200,20 +192,6 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { Ok(()) } - fn resolve_content(&self, path: &str) -> Result>, CompilerError> { - let mut file_contents = self.file_contents.borrow_mut(); - if file_contents.contains_key(path) { - // using this pattern because of mutable reference in branch below - Ok(file_contents.get(path).unwrap().clone()) - } else { - let content = fs::read_to_string(path).map_err(|e| CompilerError::FileReadError(PathBuf::from(path), e))?; - - let content = Rc::new(content.lines().map(|x| x.to_string()).collect::>()); - file_contents.insert(path.to_string(), content); - Ok(file_contents.get(path).unwrap().clone()) - } - } - /// /// Parses and stores the main program file, constructs a syntax tree, and generates a program. /// @@ -224,31 +202,7 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { let content = fs::read_to_string(&self.main_file_path) .map_err(|e| CompilerError::FileReadError(self.main_file_path.clone(), e))?; - self.parse_program_from_string(&content).map_err(|mut error| { - // Return a formatted error with file path and code text. - - let path = match error.get_path().map(|x| x.to_string()) { - // Get the file path if it exists - Some(path) => path, - - // If a file path does not exist, then insert the main file path. - None => match self.main_file_path.clone().into_os_string().into_string() { - Err(e) => return CompilerError::FileStringError(e), - Ok(path) => path, - }, - }; - - // Resolve the code text using the file path. - let content = match self.resolve_content(&path) { - Err(e) => return e, - Ok(x) => x, - }; - - // Update the formatted error. - error.set_path(&path, &content[..]); - - error - }) + self.parse_program_from_string(&content) } /// @@ -257,11 +211,6 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { /// pub fn parse_program_from_string(&mut self, program_string: &str) -> Result<(), CompilerError> { // Use the parser to construct the abstract syntax tree (ast). - let lines = program_string.lines().map(|x| x.to_string()).collect(); - self.file_contents.borrow_mut().insert( - self.main_file_path.to_str().map(|x| x.to_string()).unwrap_or_default(), - Rc::new(lines), - ); let mut ast = parse_ast(self.main_file_path.to_str().unwrap_or_default(), program_string)?; // Preform compiler optimization via canonicalizing AST if its enabled. @@ -313,28 +262,14 @@ impl<'a, F: PrimeField, G: GroupType> Compiler<'a, F, G> { /// Synthesizes the circuit with program input to verify correctness. /// pub fn compile_constraints>(&self, cs: &mut CS) -> Result { - generate_constraints::(cs, &self.asg.as_ref().unwrap(), &self.program_input).map_err(|mut error| { - if let Some(path) = error.get_path().map(|x| x.to_string()) { - let content = match self.resolve_content(&path) { - Err(e) => return e, - Ok(x) => x, - }; - error.set_path(&path, &content[..]); - } - error - }) + generate_constraints::(cs, &self.asg.as_ref().unwrap(), &self.program_input) } /// /// Synthesizes the circuit for test functions with program input. /// pub fn compile_test_constraints(self, input_pairs: InputPairs) -> Result<(u32, u32), CompilerError> { - generate_test_constraints::( - &self.asg.as_ref().unwrap(), - input_pairs, - &self.main_file_path, - &self.output_directory, - ) + generate_test_constraints::(&self.asg.as_ref().unwrap(), input_pairs, &self.output_directory) } /// diff --git a/compiler/src/console/assert.rs b/compiler/src/console/assert.rs index d10658bc2a..1c616c53d3 100644 --- a/compiler/src/console/assert.rs +++ b/compiler/src/console/assert.rs @@ -17,11 +17,7 @@ //! Enforces an assert equals statement in a compiled Leo program. use crate::{ - errors::ConsoleError, - get_indicator_value, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, + errors::ConsoleError, get_indicator_value, program::ConstrainedProgram, value::ConstrainedValue, GroupType, }; use leo_asg::{Expression, Span}; diff --git a/compiler/src/constraints/constraints.rs b/compiler/src/constraints/constraints.rs index 1d9400b5fb..5931d7a080 100644 --- a/compiler/src/constraints/constraints.rs +++ b/compiler/src/constraints/constraints.rs @@ -18,7 +18,7 @@ use crate::{errors::CompilerError, ConstrainedProgram, GroupType, OutputBytes, OutputFile}; use leo_asg::Program; -use leo_ast::{Input, LeoError}; +use leo_ast::Input; use leo_input::LeoInputParser; use leo_package::inputs::InputPairs; @@ -50,7 +50,6 @@ pub fn generate_constraints<'a, F: PrimeField, G: GroupType, CS: ConstraintSy pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType>( program: &Program<'a>, input: InputPairs, - main_file_path: &Path, output_directory: &Path, ) -> Result<(u32, u32), CompilerError> { let mut resolved_program = ConstrainedProgram::::new(program.clone()); @@ -78,7 +77,7 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType>( let input_file = function .annotations .iter() - .find(|x| x.name.name == "test") + .find(|x| x.name.name.as_ref() == "test") .unwrap() .arguments .get(0); @@ -87,11 +86,11 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType>( Some(file_id) => { let file_name = file_id.clone(); - output_file_name = file_name.clone(); + output_file_name = file_name.to_string(); - match input.pairs.get(&file_name) { + match input.pairs.get(file_name.as_ref()) { Some(pair) => pair.to_owned(), - None => return Err(CompilerError::InvalidTestContext(file_name)), + None => return Err(CompilerError::InvalidTestContext(file_name.to_string())), } } None => default.ok_or(CompilerError::NoTestInput)?, @@ -135,8 +134,7 @@ pub fn generate_test_constraints<'a, F: PrimeField, G: GroupType>( } (false, _) => { // Set file location of error - let mut error = result.unwrap_err(); - error.set_path(main_file_path.to_str().unwrap_or_default(), &[]); + let error = result.unwrap_err(); tracing::error!("{} failed due to error\n\n{}\n", full_test_name, error); diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index 78b0f5735a..f9c5f9919e 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -82,30 +82,4 @@ pub enum CompilerError { CanonicalizeError(#[from] CanonicalizeError), } -impl LeoError for CompilerError { - fn get_path(&self) -> Option<&str> { - match self { - CompilerError::SyntaxError(error) => error.get_path(), - CompilerError::ImportError(error) => error.get_path(), - CompilerError::ImportParserError(error) => error.get_path(), - CompilerError::InputParserError(error) => error.get_path(), - CompilerError::FunctionError(error) => error.get_path(), - CompilerError::OutputStringError(error) => error.get_path(), - CompilerError::AsgConvertError(error) => error.get_path(), - _ => None, - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - CompilerError::SyntaxError(error) => error.set_path(path, contents), - CompilerError::ImportError(error) => error.set_path(path, contents), - CompilerError::ImportParserError(error) => error.set_path(path, contents), - CompilerError::InputParserError(error) => error.set_path(path, contents), - CompilerError::FunctionError(error) => error.set_path(path, contents), - CompilerError::OutputStringError(error) => error.set_path(path, contents), - CompilerError::AsgConvertError(error) => error.set_path(path, contents), - _ => {} - } - } -} +impl LeoError for CompilerError {} diff --git a/compiler/src/errors/console.rs b/compiler/src/errors/console.rs index 58391c57fe..62ee02446a 100644 --- a/compiler/src/errors/console.rs +++ b/compiler/src/errors/console.rs @@ -26,21 +26,7 @@ pub enum ConsoleError { Expression(#[from] ExpressionError), } -impl LeoError for ConsoleError { - fn get_path(&self) -> Option<&str> { - match self { - ConsoleError::Error(error) => error.get_path(), - ConsoleError::Expression(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - ConsoleError::Error(error) => error.set_path(path, contents), - ConsoleError::Expression(error) => error.set_path(path, contents), - } - } -} +impl LeoError for ConsoleError {} impl ConsoleError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs index cfa4c2525d..0e4f41a99a 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -45,33 +45,7 @@ pub enum ExpressionError { ValueError(#[from] ValueError), } -impl LeoError for ExpressionError { - fn get_path(&self) -> Option<&str> { - match self { - ExpressionError::AddressError(error) => error.get_path(), - ExpressionError::BooleanError(error) => error.get_path(), - ExpressionError::Error(error) => error.get_path(), - ExpressionError::FieldError(error) => error.get_path(), - ExpressionError::FunctionError(error) => error.get_path(), - ExpressionError::GroupError(error) => error.get_path(), - ExpressionError::IntegerError(error) => error.get_path(), - ExpressionError::ValueError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - ExpressionError::AddressError(error) => error.set_path(path, contents), - ExpressionError::BooleanError(error) => error.set_path(path, contents), - ExpressionError::Error(error) => error.set_path(path, contents), - ExpressionError::FieldError(error) => error.set_path(path, contents), - ExpressionError::FunctionError(error) => error.set_path(path, contents), - ExpressionError::GroupError(error) => error.set_path(path, contents), - ExpressionError::IntegerError(error) => error.set_path(path, contents), - ExpressionError::ValueError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for ExpressionError {} impl ExpressionError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index 42beafc154..9da4000513 100644 --- a/compiler/src/errors/function.rs +++ b/compiler/src/errors/function.rs @@ -15,15 +15,8 @@ // along with the Leo library. If not, see . use crate::errors::{ - AddressError, - BooleanError, - ExpressionError, - FieldError, - GroupError, - IntegerError, - OutputBytesError, - StatementError, - ValueError, + AddressError, BooleanError, ExpressionError, FieldError, GroupError, IntegerError, OutputBytesError, + StatementError, ValueError, }; use leo_asg::AsgConvertError; use leo_ast::{FormattedError, LeoError, Span}; @@ -64,39 +57,7 @@ pub enum FunctionError { ImportASGError(#[from] AsgConvertError), } -impl LeoError for FunctionError { - fn get_path(&self) -> Option<&str> { - match self { - FunctionError::AddressError(error) => error.get_path(), - FunctionError::BooleanError(error) => error.get_path(), - FunctionError::ExpressionError(error) => error.get_path(), - FunctionError::Error(error) => error.get_path(), - FunctionError::FieldError(error) => error.get_path(), - FunctionError::GroupError(error) => error.get_path(), - FunctionError::IntegerError(error) => error.get_path(), - FunctionError::OutputStringError(error) => error.get_path(), - FunctionError::StatementError(error) => error.get_path(), - FunctionError::ValueError(error) => error.get_path(), - FunctionError::ImportASGError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - FunctionError::AddressError(error) => error.set_path(path, contents), - FunctionError::BooleanError(error) => error.set_path(path, contents), - FunctionError::ExpressionError(error) => error.set_path(path, contents), - FunctionError::Error(error) => error.set_path(path, contents), - FunctionError::FieldError(error) => error.set_path(path, contents), - FunctionError::GroupError(error) => error.set_path(path, contents), - FunctionError::IntegerError(error) => error.set_path(path, contents), - FunctionError::OutputStringError(error) => error.set_path(path, contents), - FunctionError::StatementError(error) => error.set_path(path, contents), - FunctionError::ValueError(error) => error.set_path(path, contents), - FunctionError::ImportASGError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for FunctionError {} impl FunctionError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/import.rs b/compiler/src/errors/import.rs index a61b41000f..dde6ce1644 100644 --- a/compiler/src/errors/import.rs +++ b/compiler/src/errors/import.rs @@ -22,19 +22,7 @@ pub enum ImportError { Error(#[from] FormattedError), } -impl LeoError for ImportError { - fn get_path(&self) -> Option<&str> { - match self { - ImportError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - ImportError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for ImportError {} impl ImportError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/output_bytes.rs b/compiler/src/errors/output_bytes.rs index 0dd08b026b..460d21f876 100644 --- a/compiler/src/errors/output_bytes.rs +++ b/compiler/src/errors/output_bytes.rs @@ -30,23 +30,7 @@ pub enum OutputBytesError { AsgConvertError(#[from] AsgConvertError), } -impl LeoError for OutputBytesError { - fn get_path(&self) -> Option<&str> { - match self { - OutputBytesError::Error(error) => error.get_path(), - OutputBytesError::ValueError(error) => error.get_path(), - OutputBytesError::AsgConvertError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - OutputBytesError::Error(error) => error.set_path(path, contents), - OutputBytesError::ValueError(error) => error.set_path(path, contents), - OutputBytesError::AsgConvertError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for OutputBytesError {} impl OutputBytesError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/statement.rs b/compiler/src/errors/statement.rs index 4255d273ad..b3994ee310 100644 --- a/compiler/src/errors/statement.rs +++ b/compiler/src/errors/statement.rs @@ -42,31 +42,7 @@ pub enum StatementError { ValueError(#[from] ValueError), } -impl LeoError for StatementError { - fn get_path(&self) -> Option<&str> { - match self { - StatementError::AddressError(error) => error.get_path(), - StatementError::BooleanError(error) => error.get_path(), - StatementError::Error(error) => error.get_path(), - StatementError::ExpressionError(error) => error.get_path(), - StatementError::IntegerError(error) => error.get_path(), - StatementError::MacroError(error) => error.get_path(), - StatementError::ValueError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - StatementError::AddressError(error) => error.set_path(path, contents), - StatementError::BooleanError(error) => error.set_path(path, contents), - StatementError::Error(error) => error.set_path(path, contents), - StatementError::ExpressionError(error) => error.set_path(path, contents), - StatementError::IntegerError(error) => error.set_path(path, contents), - StatementError::MacroError(error) => error.set_path(path, contents), - StatementError::ValueError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for StatementError {} impl StatementError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/address.rs b/compiler/src/errors/value/address.rs index 6bcae566f9..73a499705c 100644 --- a/compiler/src/errors/value/address.rs +++ b/compiler/src/errors/value/address.rs @@ -24,19 +24,7 @@ pub enum AddressError { Error(#[from] FormattedError), } -impl LeoError for AddressError { - fn get_path(&self) -> Option<&str> { - match self { - AddressError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - AddressError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for AddressError {} impl AddressError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/boolean.rs b/compiler/src/errors/value/boolean.rs index abb5cafab3..71b740dff6 100644 --- a/compiler/src/errors/value/boolean.rs +++ b/compiler/src/errors/value/boolean.rs @@ -23,19 +23,7 @@ pub enum BooleanError { Error(#[from] FormattedError), } -impl LeoError for BooleanError { - fn get_path(&self) -> Option<&str> { - match self { - BooleanError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - BooleanError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for BooleanError {} impl BooleanError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/field.rs b/compiler/src/errors/value/field.rs index 463996d540..87de99b995 100644 --- a/compiler/src/errors/value/field.rs +++ b/compiler/src/errors/value/field.rs @@ -23,19 +23,7 @@ pub enum FieldError { Error(#[from] FormattedError), } -impl LeoError for FieldError { - fn get_path(&self) -> Option<&str> { - match self { - FieldError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - FieldError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for FieldError {} impl FieldError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/group.rs b/compiler/src/errors/value/group.rs index c1d5fda7c6..ae3bd107d0 100644 --- a/compiler/src/errors/value/group.rs +++ b/compiler/src/errors/value/group.rs @@ -23,19 +23,7 @@ pub enum GroupError { Error(#[from] FormattedError), } -impl LeoError for GroupError { - fn get_path(&self) -> Option<&str> { - match self { - GroupError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - GroupError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for GroupError {} impl GroupError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/integer.rs b/compiler/src/errors/value/integer.rs index eb0096e400..8fecda685c 100644 --- a/compiler/src/errors/value/integer.rs +++ b/compiler/src/errors/value/integer.rs @@ -25,19 +25,7 @@ pub enum IntegerError { Error(#[from] FormattedError), } -impl LeoError for IntegerError { - fn get_path(&self) -> Option<&str> { - match self { - IntegerError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - IntegerError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for IntegerError {} impl IntegerError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/errors/value/value.rs b/compiler/src/errors/value/value.rs index d3afeb8f73..90b9ef29b2 100644 --- a/compiler/src/errors/value/value.rs +++ b/compiler/src/errors/value/value.rs @@ -38,29 +38,7 @@ pub enum ValueError { IntegerError(#[from] IntegerError), } -impl LeoError for ValueError { - fn get_path(&self) -> Option<&str> { - match self { - ValueError::AddressError(error) => error.get_path(), - ValueError::BooleanError(error) => error.get_path(), - ValueError::Error(error) => error.get_path(), - ValueError::FieldError(error) => error.get_path(), - ValueError::GroupError(error) => error.get_path(), - ValueError::IntegerError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - ValueError::AddressError(error) => error.set_path(path, contents), - ValueError::BooleanError(error) => error.set_path(path, contents), - ValueError::Error(error) => error.set_path(path, contents), - ValueError::FieldError(error) => error.set_path(path, contents), - ValueError::GroupError(error) => error.set_path(path, contents), - ValueError::IntegerError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for ValueError {} impl ValueError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/compiler/src/expression/circuit/circuit.rs b/compiler/src/expression/circuit/circuit.rs index 91ab5feb78..d5630a741f 100644 --- a/compiler/src/expression/circuit/circuit.rs +++ b/compiler/src/expression/circuit/circuit.rs @@ -42,7 +42,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { // type checking is already done in asg for (name, inner) in expr.values.iter() { let target = members - .get(&name.name) + .get(name.name.as_ref()) .expect("illegal name in asg circuit init expression"); match target { CircuitMember::Variable(_type_) => { diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 828cf2898d..5377b591a5 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -24,8 +24,7 @@ use crate::{ relational::*, resolve_core_circuit, value::{Address, ConstrainedValue, Integer}, - FieldType, - GroupType, + FieldType, GroupType, }; use leo_asg::{expression::*, ConstValue, Expression, Node, Span}; @@ -41,7 +40,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { span: &Span, ) -> Result, ExpressionError> { Ok(match value { - ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.clone(), span)?), + ConstValue::Address(value) => ConstrainedValue::Address(Address::constant(value.to_string(), span)?), ConstValue::Boolean(value) => ConstrainedValue::Boolean(Boolean::Constant(*value)), ConstValue::Field(value) => ConstrainedValue::Field(FieldType::constant(value.to_string(), span)?), ConstValue::Group(value) => ConstrainedValue::Group(G::constant(value, span)?), diff --git a/compiler/src/function/input/input_keyword.rs b/compiler/src/function/input/input_keyword.rs index 9db1bcbd6c..9db9e13b1e 100644 --- a/compiler/src/function/input/input_keyword.rs +++ b/compiler/src/function/input/input_keyword.rs @@ -38,19 +38,19 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { // Create an identifier for each input variable let registers_name = Identifier { - name: REGISTERS_VARIABLE_NAME.to_string(), + name: REGISTERS_VARIABLE_NAME.into(), span: span.clone(), }; let record_name = Identifier { - name: RECORD_VARIABLE_NAME.to_string(), + name: RECORD_VARIABLE_NAME.into(), span: span.clone(), }; let state_name = Identifier { - name: STATE_VARIABLE_NAME.to_string(), + name: STATE_VARIABLE_NAME.into(), span: span.clone(), }; let state_leaf_name = Identifier { - name: STATE_LEAF_VARIABLE_NAME.to_string(), + name: STATE_LEAF_VARIABLE_NAME.into(), span: span.clone(), }; @@ -73,7 +73,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let mut members = Vec::with_capacity(sections.len()); for (name, values) in sections { - let sub_circuit = match expected_type.members.borrow().get(&name.name) { + let sub_circuit = match expected_type.members.borrow().get(name.name.as_ref()) { Some(CircuitMember::Variable(Type::Circuit(circuit))) => *circuit, _ => panic!("illegal input type definition from asg"), }; diff --git a/compiler/src/function/input/input_section.rs b/compiler/src/function/input/input_section.rs index e188b82f3b..1fc8b1f988 100644 --- a/compiler/src/function/input/input_section.rs +++ b/compiler/src/function/input/input_section.rs @@ -36,7 +36,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { // Allocate each section definition as a circuit member value for (parameter, option) in section.into_iter() { let section_members = expected_type.members.borrow(); - let expected_type = match section_members.get(¶meter.variable.name) { + let expected_type = match section_members.get(parameter.variable.name.as_ref()) { Some(CircuitMember::Variable(inner)) => inner, _ => continue, // present, but unused }; diff --git a/compiler/src/function/input/main_function_input.rs b/compiler/src/function/input/main_function_input.rs index 5eab3a9a7c..abe2da156c 100644 --- a/compiler/src/function/input/main_function_input.rs +++ b/compiler/src/function/input/main_function_input.rs @@ -21,9 +21,7 @@ use crate::{ errors::FunctionError, program::ConstrainedProgram, value::{ - boolean::input::bool_from_input, - field::input::field_from_input, - group::input::group_from_input, + boolean::input::bool_from_input, field::input::field_from_input, group::input::group_from_input, ConstrainedValue, }, FieldType, diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index c22f7154c2..8884be0e9f 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -62,11 +62,11 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let input_variable = input_variable.get().borrow(); let name = input_variable.name.name.clone(); - let input_value = match (input_variable.const_, input.get(&name), input.get_constant(&name)) { + let input_value = match (input_variable.const_, input.get(&name), input.get_constant(name.as_ref())) { // If variable is in both [main] and [constants] sections - error. (_, Some(_), Some(_)) => { return Err(FunctionError::double_input_declaration( - name.clone(), + name.to_string(), &function.span.clone().unwrap_or_default(), )); } @@ -89,21 +89,21 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { // Function argument is const, input is not. (true, Some(_), None) => { return Err(FunctionError::expected_const_input( - name.clone(), + name.to_string(), &function.span.clone().unwrap_or_default(), )); } // Input is const, function argument is not. (false, None, Some(_)) => { return Err(FunctionError::expected_non_const_input( - name.clone(), + name.to_string(), &function.span.clone().unwrap_or_default(), )); } // When not found - Error out. (_, _, _) => { return Err(FunctionError::input_not_found( - name.clone(), + name.to_string(), &function.span.clone().unwrap_or_default(), )); } diff --git a/compiler/src/function/mut_target.rs b/compiler/src/function/mut_target.rs index 913cd974ce..fd00543b67 100644 --- a/compiler/src/function/mut_target.rs +++ b/compiler/src/function/mut_target.rs @@ -17,21 +17,11 @@ //! Resolves assignees in a compiled Leo program. use crate::{ - errors::StatementError, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, - ResolvedAssigneeAccess, + errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, ResolvedAssigneeAccess, }; use leo_asg::{ - ArrayAccessExpression, - ArrayRangeAccessExpression, - CircuitAccessExpression, - Expression, - Node, - Span, - TupleAccessExpression, - Variable, + ArrayAccessExpression, ArrayRangeAccessExpression, CircuitAccessExpression, Expression, Node, Span, + TupleAccessExpression, Variable, }; use snarkvm_fields::PrimeField; diff --git a/compiler/src/function/result/result.rs b/compiler/src/function/result/result.rs index f29669983d..1bff1822cc 100644 --- a/compiler/src/function/result/result.rs +++ b/compiler/src/function/result/result.rs @@ -17,11 +17,7 @@ //! Enforces that one return value is produced in a compiled Leo program. use crate::{ - errors::StatementError, - get_indicator_value, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, + errors::StatementError, get_indicator_value, program::ConstrainedProgram, value::ConstrainedValue, GroupType, }; use leo_asg::{Span, Type}; diff --git a/compiler/src/output/output_file.rs b/compiler/src/output/output_file.rs index f9dd6eeda1..e588f1909a 100644 --- a/compiler/src/output/output_file.rs +++ b/compiler/src/output/output_file.rs @@ -21,8 +21,7 @@ use crate::errors::OutputFileError; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/compiler/src/prelude/blake2s.rs b/compiler/src/prelude/blake2s.rs index 17e47b1196..5fb05f25b8 100644 --- a/compiler/src/prelude/blake2s.rs +++ b/compiler/src/prelude/blake2s.rs @@ -56,7 +56,7 @@ impl<'a, F: PrimeField, G: GroupType> CoreCircuit<'a, F, G> for Blake2s { mut arguments: Vec>, ) -> Result, ExpressionError> { assert_eq!(arguments.len(), 2); // asg enforced - assert!(function.name.borrow().name == "hash"); // asg enforced + assert!(function.name.borrow().name.as_ref() == "hash"); // asg enforced assert!(target.is_none()); // asg enforced let input = unwrap_argument(arguments.remove(1)); let seed = unwrap_argument(arguments.remove(0)); diff --git a/compiler/src/statement/conditional/conditional.rs b/compiler/src/statement/conditional/conditional.rs index 5b86992414..c767d14293 100644 --- a/compiler/src/statement/conditional/conditional.rs +++ b/compiler/src/statement/conditional/conditional.rs @@ -17,12 +17,8 @@ //! Methods to enforce constraints on statements in a compiled Leo program. use crate::{ - errors::StatementError, - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, - IndicatorAndConstrainedValue, - StatementResult, + errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, + IndicatorAndConstrainedValue, StatementResult, }; use leo_asg::ConditionalStatement; diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index 0a2b3226af..6b749ea419 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -17,11 +17,7 @@ //! Enforces an iteration statement in a compiled Leo program. use crate::{ - program::ConstrainedProgram, - value::ConstrainedValue, - GroupType, - IndicatorAndConstrainedValue, - Integer, + program::ConstrainedProgram, value::ConstrainedValue, GroupType, IndicatorAndConstrainedValue, Integer, StatementResult, }; use leo_asg::IterationStatement; diff --git a/compiler/src/value/address/address.rs b/compiler/src/value/address/address.rs index fcd606f81b..1bcf1dff4b 100644 --- a/compiler/src/value/address/address.rs +++ b/compiler/src/value/address/address.rs @@ -198,7 +198,11 @@ impl ConditionalEqGadget for Address { } fn cond_select_helper(first: &Address, second: &Address, cond: bool) -> Address { - if cond { first.clone() } else { second.clone() } + if cond { + first.clone() + } else { + second.clone() + } } impl CondSelectGadget for Address { diff --git a/compiler/src/value/field/field_type.rs b/compiler/src/value/field/field_type.rs index 1280518aeb..d8afed1ff2 100644 --- a/compiler/src/value/field/field_type.rs +++ b/compiler/src/value/field/field_type.rs @@ -289,7 +289,11 @@ impl CondSelectGadget for FieldType { second: &Self, ) -> Result { if let Boolean::Constant(cond) = *cond { - if cond { Ok(first.clone()) } else { Ok(second.clone()) } + if cond { + Ok(first.clone()) + } else { + Ok(second.clone()) + } } else { let first_gadget = first.allocated(&mut cs)?; let second_gadget = second.allocated(&mut cs)?; diff --git a/compiler/src/value/group/targets/edwards_bls12.rs b/compiler/src/value/group/targets/edwards_bls12.rs index 4b48511ef0..4bf55a017e 100644 --- a/compiler/src/value/group/targets/edwards_bls12.rs +++ b/compiler/src/value/group/targets/edwards_bls12.rs @@ -20,8 +20,7 @@ use leo_asg::{GroupCoordinate, GroupValue, Span}; use snarkvm_curves::{ edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq}, templates::twisted_edwards_extended::GroupAffine, - AffineCurve, - TEModelParameters, + AffineCurve, TEModelParameters, }; use snarkvm_fields::{Fp256, One, Zero}; use snarkvm_gadgets::{ @@ -482,7 +481,11 @@ impl CondSelectGadget for EdwardsGroupType { second: &Self, ) -> Result { if let Boolean::Constant(cond) = *cond { - if cond { Ok(first.clone()) } else { Ok(second.clone()) } + if cond { + Ok(first.clone()) + } else { + Ok(second.clone()) + } } else { let first_gadget = first.allocated(cs.ns(|| "first"))?; let second_gadget = second.allocated(cs.ns(|| "second"))?; diff --git a/compiler/src/value/integer/macros.rs b/compiler/src/value/integer/macros.rs index 932a646fa4..de26e63e71 100644 --- a/compiler/src/value/integer/macros.rs +++ b/compiler/src/value/integer/macros.rs @@ -19,11 +19,14 @@ use snarkvm_gadgets::traits::utilities::{ int::{Int128, Int16, Int32, Int64, Int8}, uint::{UInt128, UInt16, UInt32, UInt64, UInt8}, }; +use std::convert::TryInto; use std::fmt::Debug; pub trait IntegerTrait: Sized + Clone + Debug { fn get_value(&self) -> Option; + fn get_index(&self) -> Option; + fn get_bits(&self) -> Vec; } @@ -34,6 +37,10 @@ macro_rules! integer_trait_impl { self.value.map(|num| num.to_string()) } + fn get_index(&self) -> Option { + self.value.map(|num| num.try_into().ok()).flatten() + } + fn get_bits(&self) -> Vec { self.bits.clone() } diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index fb01748d2f..4f57c064fe 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -15,12 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - get_output, - parse_program, - parse_program_with_input, + assert_satisfied, expect_asg_error, expect_compiler_error, get_output, parse_program, parse_program_with_input, EdwardsTestCompiler, }; diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index 4051bf83d9..23d300c4cc 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -15,12 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - get_output, - parse_program, - parse_program_with_input, + assert_satisfied, expect_asg_error, expect_compiler_error, get_output, parse_program, parse_program_with_input, EdwardsTestCompiler, }; diff --git a/compiler/tests/console/mod.rs b/compiler/tests/console/mod.rs index d3ce931675..0726ed148f 100644 --- a/compiler/tests/console/mod.rs +++ b/compiler/tests/console/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - parse_program, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, parse_program, parse_program_with_input, }; use leo_ast::InputValue; diff --git a/compiler/tests/core/packages/unstable/blake2s/mod.rs b/compiler/tests/core/packages/unstable/blake2s/mod.rs index ce9a23b2f3..c0be4c09be 100644 --- a/compiler/tests/core/packages/unstable/blake2s/mod.rs +++ b/compiler/tests/core/packages/unstable/blake2s/mod.rs @@ -15,12 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - generate_main_input, - get_output, - parse_program, - parse_program_with_input, + assert_satisfied, expect_asg_error, generate_main_input, get_output, parse_program, parse_program_with_input, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs index e62e07260e..2152b34b45 100644 --- a/compiler/tests/integers/i128/mod.rs +++ b/compiler/tests/integers/i128/mod.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs index 49b45f5b3e..4b5b265979 100644 --- a/compiler/tests/integers/i16/mod.rs +++ b/compiler/tests/integers/i16/mod.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs index ee9e25701a..0589f2e3e4 100644 --- a/compiler/tests/integers/i32/mod.rs +++ b/compiler/tests/integers/i32/mod.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs index 066ac9956f..9ac964b71f 100644 --- a/compiler/tests/integers/i64/mod.rs +++ b/compiler/tests/integers/i64/mod.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs index 9133a72248..5114e91a32 100644 --- a/compiler/tests/integers/i8/mod.rs +++ b/compiler/tests/integers/i8/mod.rs @@ -15,10 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 2c110af0a5..984930776e 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - integers::IntegerTester, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index b4b202b9da..9ac9c2c48a 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - integers::IntegerTester, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index 920fc6ed5b..f1ccc0588d 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - integers::IntegerTester, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index ec86c868f1..7a21e5c0e4 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - integers::IntegerTester, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index a61e28246d..c328b75e07 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -15,11 +15,7 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_asg_error, - expect_compiler_error, - generate_main_input, - integers::IntegerTester, + assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index 96069ffe54..9f8a03bc1e 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -41,10 +41,7 @@ pub mod tuples; use leo_asg::{new_alloc_context, new_context, AsgContext}; use leo_ast::{InputValue, MainInput}; use leo_compiler::{ - compiler::Compiler, - errors::CompilerError, - group::targets::edwards_bls12::EdwardsGroupType, - ConstrainedValue, + compiler::Compiler, errors::CompilerError, group::targets::edwards_bls12::EdwardsGroupType, ConstrainedValue, OutputBytes, }; use leo_input::types::{IntegerType, U32Type, UnsignedIntegerType}; diff --git a/compiler/tests/statements/conditional/mod.rs b/compiler/tests/statements/conditional/mod.rs index c57f7974de..30c9180e92 100644 --- a/compiler/tests/statements/conditional/mod.rs +++ b/compiler/tests/statements/conditional/mod.rs @@ -15,14 +15,8 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, - expect_compiler_error, - generate_main_input, - generate_test_input_u32, - get_output, - parse_program, - parse_program_with_input, - EdwardsTestCompiler, + assert_satisfied, expect_compiler_error, generate_main_input, generate_test_input_u32, get_output, parse_program, + parse_program_with_input, EdwardsTestCompiler, }; use leo_ast::InputValue; diff --git a/imports/src/errors/import_parser.rs b/imports/src/errors/import_parser.rs index 1272d7e1e5..87a3e8b03c 100644 --- a/imports/src/errors/import_parser.rs +++ b/imports/src/errors/import_parser.rs @@ -33,25 +33,7 @@ pub enum ImportParserError { AsgConvertError(#[from] AsgConvertError), } -impl LeoError for ImportParserError { - fn get_path(&self) -> Option<&str> { - match self { - ImportParserError::Error(error) => error.get_path(), - ImportParserError::SyntaxError(error) => error.get_path(), - ImportParserError::AsgConvertError(error) => error.get_path(), - ImportParserError::DeprecatedError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - ImportParserError::Error(error) => error.set_path(path, contents), - ImportParserError::SyntaxError(error) => error.set_path(path, contents), - ImportParserError::AsgConvertError(error) => error.set_path(path, contents), - ImportParserError::DeprecatedError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for ImportParserError {} impl Into for ImportParserError { fn into(self) -> AsgConvertError { diff --git a/leo/api.rs b/leo/api.rs index 23e12b3578..5cd384479b 100644 --- a/leo/api.rs +++ b/leo/api.rs @@ -17,8 +17,7 @@ use anyhow::{anyhow, Error, Result}; use reqwest::{ blocking::{Client, Response}, - Method, - StatusCode, + Method, StatusCode, }; use serde::Serialize; diff --git a/leo/commands/package/clone.rs b/leo/commands/package/clone.rs index 5b5e6acdcf..c899cbe046 100644 --- a/leo/commands/package/clone.rs +++ b/leo/commands/package/clone.rs @@ -20,8 +20,7 @@ use anyhow::{anyhow, Result}; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::{Read, Write}, path::Path, diff --git a/leo/config.rs b/leo/config.rs index 11de847b70..848533f05b 100644 --- a/leo/config.rs +++ b/leo/config.rs @@ -16,9 +16,7 @@ use std::{ fs::{ - create_dir_all, - File, - {self}, + create_dir_all, File, {self}, }, io, io::prelude::*, diff --git a/leo/main.rs b/leo/main.rs index a0d256230c..81dc979e9e 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -23,19 +23,7 @@ pub mod updater; use commands::{ package::{Add, Clone, Login, Logout, Publish, Remove}, - Build, - Clean, - Command, - Deploy, - Init, - Lint, - New, - Prove, - Run, - Setup, - Test, - Update, - Watch, + Build, Clean, Command, Deploy, Init, Lint, New, Prove, Run, Setup, Test, Update, Watch, }; use anyhow::Error; @@ -175,10 +163,13 @@ fn main() { if !opt.quiet { // init logger with optional debug flag - logger::init_logger("leo", match opt.debug { - false => 1, - true => 2, - }); + logger::init_logger( + "leo", + match opt.debug { + false => 1, + true => 2, + }, + ); } handle_error(match opt.command { diff --git a/leo/tests/mod.rs b/leo/tests/mod.rs index 7bc611f49d..9607594e4f 100644 --- a/leo/tests/mod.rs +++ b/leo/tests/mod.rs @@ -21,14 +21,7 @@ use anyhow::Result; use crate::{ commands::{ package::{Login, Logout}, - Build, - Command, - Prove, - Run, - Setup, - Test, - Update, - UpdateAutomatic, + Build, Command, Prove, Run, Setup, Test, Update, UpdateAutomatic, }, context::{create_context, Context}, }; diff --git a/package/src/inputs/input.rs b/package/src/inputs/input.rs index 3e01cbbe5d..74ca67484a 100644 --- a/package/src/inputs/input.rs +++ b/package/src/inputs/input.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/inputs/state.rs b/package/src/inputs/state.rs index 7bda80ceb7..4c7994291e 100644 --- a/package/src/inputs/state.rs +++ b/package/src/inputs/state.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/checksum.rs b/package/src/outputs/checksum.rs index 9352429973..3f56c22a76 100644 --- a/package/src/outputs/checksum.rs +++ b/package/src/outputs/checksum.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/circuit.rs b/package/src/outputs/circuit.rs index d9d0e8cced..81a528f310 100644 --- a/package/src/outputs/circuit.rs +++ b/package/src/outputs/circuit.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/proof.rs b/package/src/outputs/proof.rs index 815d6048be..6a9419b889 100644 --- a/package/src/outputs/proof.rs +++ b/package/src/outputs/proof.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/proving_key.rs b/package/src/outputs/proving_key.rs index 7e2d938bd7..35f054554d 100644 --- a/package/src/outputs/proving_key.rs +++ b/package/src/outputs/proving_key.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/verification_key.rs b/package/src/outputs/verification_key.rs index 6f7fca8797..9acfe62fc4 100644 --- a/package/src/outputs/verification_key.rs +++ b/package/src/outputs/verification_key.rs @@ -22,8 +22,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::Write, path::Path, diff --git a/package/src/root/zip.rs b/package/src/root/zip.rs index 46426b9d3e..a377e263c5 100644 --- a/package/src/root/zip.rs +++ b/package/src/root/zip.rs @@ -21,12 +21,8 @@ use crate::{ imports::IMPORTS_DIRECTORY_NAME, inputs::{INPUTS_DIRECTORY_NAME, INPUT_FILE_EXTENSION, STATE_FILE_EXTENSION}, outputs::{ - CHECKSUM_FILE_EXTENSION, - CIRCUIT_FILE_EXTENSION, - OUTPUTS_DIRECTORY_NAME, - PROOF_FILE_EXTENSION, - PROVING_KEY_FILE_EXTENSION, - VERIFICATION_KEY_FILE_EXTENSION, + CHECKSUM_FILE_EXTENSION, CIRCUIT_FILE_EXTENSION, OUTPUTS_DIRECTORY_NAME, PROOF_FILE_EXTENSION, + PROVING_KEY_FILE_EXTENSION, VERIFICATION_KEY_FILE_EXTENSION, }, root::{MANIFEST_FILENAME, README_FILENAME}, source::{SOURCE_DIRECTORY_NAME, SOURCE_FILE_EXTENSION}, @@ -36,8 +32,7 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, - {self}, + File, {self}, }, io::{Read, Write}, path::Path, diff --git a/package/tests/mod.rs b/package/tests/mod.rs index 8f72a16b3e..c04bfade1f 100644 --- a/package/tests/mod.rs +++ b/package/tests/mod.rs @@ -22,8 +22,7 @@ pub mod manifest; use lazy_static::lazy_static; use std::{ cell::RefCell, - env, - fs, + env, fs, path::PathBuf, sync::atomic::{AtomicUsize, Ordering}, }; diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 1a3a25e7d5..d2a9ba9557 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -48,6 +48,9 @@ version = "0.3" [dependencies.indexmap] version = "1.6" +[dependencies.tendril] +version = "0.4" + [features] default = [ ] ci_skip = [ ] diff --git a/parser/src/errors/deprecated.rs b/parser/src/errors/deprecated.rs index 5a03d59d3b..d41857b161 100644 --- a/parser/src/errors/deprecated.rs +++ b/parser/src/errors/deprecated.rs @@ -28,19 +28,7 @@ impl DeprecatedError { } } -impl LeoError for DeprecatedError { - fn get_path(&self) -> Option<&str> { - match self { - DeprecatedError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - DeprecatedError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for DeprecatedError {} impl DeprecatedError { pub fn mut_function_input(mut span: Span) -> Self { diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index c453625d94..d2c31ac72a 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -30,23 +30,7 @@ pub enum SyntaxError { DeprecatedError(#[from] DeprecatedError), } -impl LeoError for SyntaxError { - fn get_path(&self) -> Option<&str> { - match self { - SyntaxError::Error(error) => error.get_path(), - SyntaxError::TokenError(error) => error.get_path(), - SyntaxError::DeprecatedError(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - SyntaxError::Error(error) => error.set_path(path, contents), - SyntaxError::TokenError(error) => error.set_path(path, contents), - SyntaxError::DeprecatedError(error) => error.set_path(path, contents), - } - } -} +impl LeoError for SyntaxError {} impl SyntaxError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/parser/src/errors/token.rs b/parser/src/errors/token.rs index 3a439646a7..2b9beca504 100644 --- a/parser/src/errors/token.rs +++ b/parser/src/errors/token.rs @@ -22,19 +22,7 @@ pub enum TokenError { Error(#[from] FormattedError), } -impl LeoError for TokenError { - fn get_path(&self) -> Option<&str> { - match self { - TokenError::Error(error) => error.get_path(), - } - } - - fn set_path(&mut self, path: &str, contents: &[String]) { - match self { - TokenError::Error(error) => error.set_path(path, contents), - } - } -} +impl LeoError for TokenError {} impl TokenError { fn new_from_span(message: String, span: &Span) -> Self { diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index 1c3f41f53e..99940889ea 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -18,6 +18,7 @@ use std::unimplemented; use crate::{tokenizer::*, SyntaxError, SyntaxResult, Token, KEYWORD_TOKENS}; use leo_ast::*; +use tendril::format_tendril; /// Stores a program in tokenized format plus additional context. /// May be converted into a [`Program`] AST by parsing all tokens. @@ -149,11 +150,11 @@ impl ParserContext { span, }) => { *i -= 1; - GroupCoordinate::Number(format!("-{}", value), span.clone()) + GroupCoordinate::Number(format_tendril!("-{}", value), span.clone()) } _ => GroupCoordinate::SignLow, }, - Token::Ident(x) if x == "_" => GroupCoordinate::Inferred, + Token::Ident(x) if x.as_ref() == "_" => GroupCoordinate::Inferred, Token::Int(value) => GroupCoordinate::Number(value.clone(), token.span.clone()), _ => return None, }) @@ -280,7 +281,7 @@ impl ParserContext { pub fn expect_loose_identifier(&mut self) -> SyntaxResult { if let Some(token) = self.eat_any(KEYWORD_TOKENS) { return Ok(Identifier { - name: token.token.to_string(), + name: token.token.to_string().into(), span: token.span, }); } diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index b11d8bafce..43c88b498d 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use tendril::format_tendril; + use super::*; const INT_TYPES: &[Token] = &[ @@ -368,10 +370,17 @@ impl ParserContext { // hack for const signed integer overflow issues if matches!(operation, UnaryOperation::Negate) { if let Expression::Value(ValueExpression::Integer(type_, value, span)) = inner { - inner = Expression::Value(ValueExpression::Integer(type_, format!("-{}", value), &op.span + &span)); + inner = Expression::Value(ValueExpression::Integer( + type_, + format_tendril!("-{}", value), + &op.span + &span, + )); continue; } else if let Expression::Value(ValueExpression::Implicit(value, span)) = inner { - inner = Expression::Value(ValueExpression::Implicit(format!("-{}", value), &op.span + &span)); + inner = Expression::Value(ValueExpression::Implicit( + format_tendril!("-{}", value), + &op.span + &span, + )); continue; } } @@ -574,8 +583,8 @@ impl ParserContext { None => Expression::Value(ValueExpression::Implicit(value, span)), } } - Token::True => Expression::Value(ValueExpression::Boolean("true".to_string(), span)), - Token::False => Expression::Value(ValueExpression::Boolean("false".to_string(), span)), + Token::True => Expression::Value(ValueExpression::Boolean("true".into(), span)), + Token::False => Expression::Value(ValueExpression::Boolean("false".into(), span)), Token::AddressLit(value) => Expression::Value(ValueExpression::Address(value, span)), Token::Address => { self.expect(Token::LeftParen)?; @@ -683,7 +692,7 @@ impl ParserContext { } Token::BigSelf => { let ident = Identifier { - name: token.to_string(), + name: token.to_string().into(), span, }; if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly { @@ -694,7 +703,7 @@ impl ParserContext { } Token::Input | Token::LittleSelf => { let ident = Identifier { - name: token.to_string(), + name: token.to_string().into(), span, }; Expression::Identifier(ident) diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index 769b4733cb..d767307343 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . +use tendril::format_tendril; + use crate::KEYWORD_TOKENS; use super::*; @@ -42,7 +44,7 @@ impl ParserContext { let (id, function) = self.parse_function()?; functions.insert(id, function); } - Token::Ident(ident) if ident == "test" => { + Token::Ident(ident) if ident.as_ref() == "test" => { return Err(SyntaxError::DeprecatedError(DeprecatedError::test_function( &token.span, ))); @@ -60,7 +62,7 @@ impl ParserContext { Token::Import, Token::Circuit, Token::Function, - Token::Ident("test".to_string()), + Token::Ident("test".into()), Token::At, ], &token.span, @@ -83,7 +85,7 @@ impl ParserContext { pub fn parse_annotation(&mut self) -> SyntaxResult { let start = self.expect(Token::At)?; let name = self.expect_ident()?; - if name.name == "context" { + if name.name.as_ref() == "context" { return Err(SyntaxError::DeprecatedError(DeprecatedError::context_annotation( &name.span, ))); @@ -186,25 +188,24 @@ impl ParserContext { match &self.peek()?.token { Token::Minus => { let span = self.expect(Token::Minus)?; - base.name += "-"; base.span = base.span + span; let next = self.expect_loose_identifier()?; - base.name += &next.name; + base.name = format_tendril!("{}-{}", base.name, next.name); base.span = base.span + next.span; } Token::Int(_) => { let (num, span) = self.eat_int().unwrap(); - base.name += &num.value; + base.name = format_tendril!("{}{}", base.name, num.value); base.span = base.span + span; } Token::Ident(_) => { let next = self.expect_ident()?; - base.name += &next.name; + base.name = format_tendril!("{}{}", base.name, next.name); base.span = base.span + next.span; } x if KEYWORD_TOKENS.contains(&x) => { let next = self.expect_loose_identifier()?; - base.name += &next.name; + base.name = format_tendril!("{}{}", base.name, next.name); base.span = base.span + next.span; } _ => break, @@ -212,7 +213,7 @@ impl ParserContext { } // Return an error if the package name contains a keyword. - if let Some(token) = KEYWORD_TOKENS.iter().find(|x| x.to_string() == base.name) { + if let Some(token) = KEYWORD_TOKENS.iter().find(|x| x.to_string() == base.name.as_ref()) { return Err(SyntaxError::unexpected_str(token, "package name", &base.span)); } @@ -298,10 +299,13 @@ impl ParserContext { let member = self.parse_circuit_member()?; members.push(member); } - Ok((name.clone(), Circuit { - circuit_name: name, - members, - })) + Ok(( + name.clone(), + Circuit { + circuit_name: name, + members, + }, + )) } /// @@ -311,7 +315,7 @@ impl ParserContext { if let Some(token) = self.eat(Token::Input) { return Ok(FunctionInput::InputKeyword(InputKeyword { identifier: Identifier { - name: token.token.to_string(), + name: token.token.to_string().into(), span: token.span, }, })); @@ -320,20 +324,20 @@ impl ParserContext { let mutable = self.eat(Token::Mut); let mut name = if let Some(token) = self.eat(Token::LittleSelf) { Identifier { - name: token.token.to_string(), + name: token.token.to_string().into(), span: token.span, } } else { self.expect_ident()? }; - if name.name == "self" { + if name.name.as_ref() == "self" { if let Some(mutable) = &mutable { name.span = &mutable.span + &name.span; - name.name = "mut self".to_string(); + name.name = "mut self".to_string().into(); return Ok(FunctionInput::MutSelfKeyword(MutSelfKeyword { identifier: name })); } else if let Some(const_) = &const_ { name.span = &const_.span + &name.span; - name.name = "const self".to_string(); + name.name = "const self".to_string().into(); return Ok(FunctionInput::ConstSelfKeyword(ConstSelfKeyword { identifier: name })); } return Ok(FunctionInput::SelfKeyword(SelfKeyword { identifier: name })); @@ -383,13 +387,16 @@ impl ParserContext { None }; let block = self.parse_block()?; - Ok((name.clone(), Function { - annotations, - identifier: name, - input: inputs, - output, - span: start + block.span.clone(), - block, - })) + Ok(( + name.clone(), + Function { + annotations, + identifier: name, + input: inputs, + output, + span: start + block.span.clone(), + block, + }, + )) } } diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index 0801bf4cf4..c217089d89 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -37,16 +37,7 @@ pub type SyntaxResult = Result; /// Creates a new program from a given file path and source code text. pub fn parse(path: &str, source: &str) -> SyntaxResult { - let mut tokens = ParserContext::new(crate::tokenize(path, source)?); + let mut tokens = ParserContext::new(crate::tokenize(path, source.into())?); - match tokens.parse_program() { - Ok(x) => Ok(x), - Err(mut e) => { - e.set_path( - path, - &source.lines().map(|x| x.to_string()).collect::>()[..], - ); - Err(e) - } - } + tokens.parse_program() } diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index 76639f8365..fe049bc093 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -17,6 +17,7 @@ use crate::tokenizer::{FormattedStringPart, Token}; use leo_ast::Span; use serde::{Deserialize, Serialize}; +use tendril::StrTendril; use std::fmt; @@ -24,13 +25,13 @@ use std::fmt; /// Returns a reference to bytes from the given input if the given string is equal to the bytes, /// otherwise returns [`None`]. /// -fn eat<'a>(input: &'a [u8], wanted: &str) -> Option<&'a [u8]> { +fn eat<'a>(input: &'a [u8], wanted: &str) -> Option { let wanted = wanted.as_bytes(); if input.len() < wanted.len() { return None; } if &input[0..wanted.len()] == wanted { - return Some(&input[wanted.len()..]); + return Some(wanted.len()); } None } @@ -39,10 +40,11 @@ fn eat<'a>(input: &'a [u8], wanted: &str) -> Option<&'a [u8]> { /// Returns a reference to the bytes of an identifier and the remaining bytes from the given input. /// Returns [`None`] if the bytes do not represent an identifier. /// -fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { - if input.is_empty() { +fn eat_identifier(input_tendril: &StrTendril) -> Option { + if input_tendril.is_empty() { return None; } + let input = input_tendril[..].as_bytes(); if !input[0].is_ascii_alphabetic() && input[0] != b'_' { return None; } @@ -53,7 +55,7 @@ fn eat_identifier(input: &[u8]) -> Option<(&[u8], &[u8])> { } i += 1; } - Some((&input[0..i], &input[i..])) + Some(input_tendril.subtendril(0, i as u32)) } impl Token { @@ -61,12 +63,13 @@ impl Token { /// Returns a reference to the remaining bytes and the bytes of a number from the given input. /// Returns [`None`] if the bytes do not represent a number. /// - fn gobble_int(input: &[u8]) -> (&[u8], Option) { - if input.is_empty() { - return (input, None); + fn gobble_int(input_tendril: &StrTendril) -> (usize, Option) { + if input_tendril.is_empty() { + return (0, None); } + let input = input_tendril[..].as_bytes(); if !input[0].is_ascii_digit() { - return (input, None); + return (0, None); } let mut i = 1; let mut is_hex = false; @@ -86,22 +89,20 @@ impl Token { i += 1; } - ( - &input[i..], - Some(Token::Int(String::from_utf8(input[0..i].to_vec()).unwrap_or_default())), - ) + (i, Some(Token::Int(input_tendril.subtendril(0, i as u32)))) } /// /// Returns a reference to the remaining bytes and the bytes of a [`Token`] from the given input. /// Returns [`None`] if the bytes do not represent a token. /// - pub(crate) fn gobble(input: &[u8]) -> (&[u8], Option) { - if input.is_empty() { - return (input, None); + pub(crate) fn gobble(input_tendril: StrTendril) -> (usize, Option) { + if input_tendril.is_empty() { + return (0, None); } + let input = input_tendril[..].as_bytes(); match input[0] { - x if x.is_ascii_whitespace() => return (&input[1..], None), + x if x.is_ascii_whitespace() => return (1, None), b'"' => { let mut i = 1; let mut in_escape = false; @@ -124,7 +125,7 @@ impl Token { } if start < i { segments.push(FormattedStringPart::Const( - String::from_utf8_lossy(&input[start..i]).to_string(), + input_tendril.subtendril(start as u32, (i - start) as u32), )); } segments.push(FormattedStringPart::Container); @@ -138,186 +139,171 @@ impl Token { i += 1; } if i == input.len() { - return (input, None); + return (0, None); } if start < i { segments.push(FormattedStringPart::Const( - String::from_utf8_lossy(&input[start..i]).to_string(), + input_tendril.subtendril(start as u32, (i - start) as u32), )); } - return (&input[(i + 1)..], Some(Token::FormattedString(segments))); + return (i + 1, Some(Token::FormattedString(segments))); } x if x.is_ascii_digit() => { - return Self::gobble_int(input); + return Self::gobble_int(&input_tendril); } b'!' => { - if let Some(input) = eat(input, "!=") { - return (input, Some(Token::NotEq)); + if let Some(len) = eat(input, "!=") { + return (len, Some(Token::NotEq)); } - return (&input[1..], Some(Token::Not)); + return (1, Some(Token::Not)); } b'?' => { - return (&input[1..], Some(Token::Question)); + return (1, Some(Token::Question)); } b'&' => { - if let Some(input) = eat(input, "&&") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::AndEq)); + if let Some(len) = eat(input, "&&") { + if let Some(inner_len) = eat(&input[len..], "=") { + return (len + inner_len, Some(Token::AndEq)); } - return (input, Some(Token::And)); - } else if let Some(input) = eat(input, "&=") { - return (input, Some(Token::BitAndEq)); + return (len, Some(Token::And)); + } else if let Some(len) = eat(input, "&=") { + return (len, Some(Token::BitAndEq)); } - return (&input[1..], Some(Token::BitAnd)); + return (1, Some(Token::BitAnd)); } - b'(' => return (&input[1..], Some(Token::LeftParen)), - b')' => return (&input[1..], Some(Token::RightParen)), + b'(' => return (1, Some(Token::LeftParen)), + b')' => return (1, Some(Token::RightParen)), b'*' => { - if let Some(input) = eat(input, "**") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ExpEq)); + if let Some(len) = eat(input, "**") { + if let Some(inner_len) = eat(&input[len..], "=") { + return (len + inner_len, Some(Token::ExpEq)); } - return (input, Some(Token::Exp)); - } else if let Some(input) = eat(input, "*=") { - return (input, Some(Token::MulEq)); + return (len, Some(Token::Exp)); + } else if let Some(len) = eat(input, "*=") { + return (len, Some(Token::MulEq)); } - return (&input[1..], Some(Token::Mul)); + return (1, Some(Token::Mul)); } b'+' => { - if let Some(input) = eat(input, "+=") { - return (input, Some(Token::AddEq)); + if let Some(len) = eat(input, "+=") { + return (len, Some(Token::AddEq)); } - return (&input[1..], Some(Token::Add)); + return (1, Some(Token::Add)); } - b',' => return (&input[1..], Some(Token::Comma)), + b',' => return (1, Some(Token::Comma)), b'-' => { - if let Some(input) = eat(input, "->") { - return (input, Some(Token::Arrow)); - } else if let Some(input) = eat(input, "-=") { - return (input, Some(Token::MinusEq)); + if let Some(len) = eat(input, "->") { + return (len, Some(Token::Arrow)); + } else if let Some(len) = eat(input, "-=") { + return (len, Some(Token::MinusEq)); } - return (&input[1..], Some(Token::Minus)); + return (1, Some(Token::Minus)); } b'.' => { - if let Some(input) = eat(input, "...") { - return (input, Some(Token::DotDotDot)); - } else if let Some(input) = eat(input, "..") { - return (input, Some(Token::DotDot)); + if let Some(len) = eat(input, "...") { + return (len, Some(Token::DotDotDot)); + } else if let Some(len) = eat(input, "..") { + return (len, Some(Token::DotDot)); } - return (&input[1..], Some(Token::Dot)); + return (1, Some(Token::Dot)); } b'/' => { if eat(input, "//").is_some() { let eol = input.iter().position(|x| *x == b'\n'); - let (input, comment) = if let Some(eol) = eol { - (&input[(eol + 1)..], &input[..eol]) - } else { - (&input[input.len()..input.len()], input) - }; - return ( - input, - Some(Token::CommentLine(String::from_utf8_lossy(comment).to_string())), - ); + let len = if let Some(eol) = eol { eol + 1 } else { input.len() }; + return (len, Some(Token::CommentLine(input_tendril.subtendril(0, len as u32)))); } else if eat(input, "/*").is_some() { if input.is_empty() { - return (input, None); + return (0, None); } let eol = input.windows(2).skip(2).position(|x| x[0] == b'*' && x[1] == b'/'); - let (input, comment) = if let Some(eol) = eol { - (&input[(eol + 4)..], &input[..eol + 4]) - } else { - (&input[input.len()..input.len()], input) - }; - return ( - input, - Some(Token::CommentBlock(String::from_utf8_lossy(comment).to_string())), - ); - } else if let Some(input) = eat(input, "/=") { - return (input, Some(Token::DivEq)); + let len = if let Some(eol) = eol { eol + 4 } else { input.len() }; + return (len, Some(Token::CommentBlock(input_tendril.subtendril(0, len as u32)))); + } else if let Some(len) = eat(input, "/=") { + return (len, Some(Token::DivEq)); } - return (&input[1..], Some(Token::Div)); + return (1, Some(Token::Div)); } b':' => { - if let Some(input) = eat(input, "::") { - return (input, Some(Token::DoubleColon)); + if let Some(len) = eat(input, "::") { + return (len, Some(Token::DoubleColon)); } else { - return (&input[1..], Some(Token::Colon)); + return (1, Some(Token::Colon)); } } - b';' => return (&input[1..], Some(Token::Semicolon)), + b';' => return (1, Some(Token::Semicolon)), b'<' => { - if let Some(input) = eat(input, "<=") { - return (input, Some(Token::LtEq)); - } else if let Some(input) = eat(input, "<<") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShlEq)); + if let Some(len) = eat(input, "<=") { + return (len, Some(Token::LtEq)); + } else if let Some(len) = eat(input, "<<") { + if let Some(inner_len) = eat(&input[len..], "=") { + return (len + inner_len, Some(Token::ShlEq)); } - return (input, Some(Token::Shl)); + return (len, Some(Token::Shl)); } - return (&input[1..], Some(Token::Lt)); + return (1, Some(Token::Lt)); } b'>' => { - if let Some(input) = eat(input, ">=") { - return (input, Some(Token::GtEq)); - } else if let Some(input) = eat(input, ">>") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShrEq)); - } else if let Some(input) = eat(input, ">") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::ShrSignedEq)); + if let Some(len) = eat(input, ">=") { + return (len, Some(Token::GtEq)); + } else if let Some(len) = eat(input, ">>") { + if let Some(inner_len) = eat(&input[len..], "=") { + return (len + inner_len, Some(Token::ShrEq)); + } else if let Some(inner_len) = eat(&input[len..], ">") { + if let Some(eq_len) = eat(&input[len + inner_len..], "=") { + return (len + inner_len + eq_len, Some(Token::ShrSignedEq)); } - return (input, Some(Token::ShrSigned)); + return (len + inner_len, Some(Token::ShrSigned)); } - return (input, Some(Token::Shr)); + return (len, Some(Token::Shr)); } - return (&input[1..], Some(Token::Gt)); + return (1, Some(Token::Gt)); } b'=' => { - if let Some(input) = eat(input, "==") { - return (input, Some(Token::Eq)); + if let Some(len) = eat(input, "==") { + return (len, Some(Token::Eq)); } - return (&input[1..], Some(Token::Assign)); + return (1, Some(Token::Assign)); } - b'@' => return (&input[1..], Some(Token::At)), - b'[' => return (&input[1..], Some(Token::LeftSquare)), - b']' => return (&input[1..], Some(Token::RightSquare)), - b'{' => return (&input[1..], Some(Token::LeftCurly)), - b'}' => return (&input[1..], Some(Token::RightCurly)), + b'@' => return (1, Some(Token::At)), + b'[' => return (1, Some(Token::LeftSquare)), + b']' => return (1, Some(Token::RightSquare)), + b'{' => return (1, Some(Token::LeftCurly)), + b'}' => return (1, Some(Token::RightCurly)), b'|' => { - if let Some(input) = eat(input, "||") { - if let Some(input) = eat(input, "=") { - return (input, Some(Token::OrEq)); + if let Some(len) = eat(input, "||") { + if let Some(inner_len) = eat(&input[len..], "=") { + return (len + inner_len, Some(Token::OrEq)); } - return (input, Some(Token::Or)); - } else if let Some(input) = eat(input, "|=") { - return (input, Some(Token::BitOrEq)); + return (len, Some(Token::Or)); + } else if let Some(len) = eat(input, "|=") { + return (len, Some(Token::BitOrEq)); } - return (&input[1..], Some(Token::BitOr)); + return (1, Some(Token::BitOr)); } b'^' => { - if let Some(input) = eat(input, "^=") { - return (input, Some(Token::BitXorEq)); + if let Some(len) = eat(input, "^=") { + return (len, Some(Token::BitXorEq)); } - return (&input[1..], Some(Token::BitXor)); + return (1, Some(Token::BitXor)); } - b'~' => return (&input[1..], Some(Token::BitNot)), + b'~' => return (1, Some(Token::BitNot)), b'%' => { - if let Some(input) = eat(input, "%=") { - return (input, Some(Token::ModEq)); + if let Some(len) = eat(input, "%=") { + return (len, Some(Token::ModEq)); } - return (&input[1..], Some(Token::Mod)); + return (1, Some(Token::Mod)); } _ => (), } - if let Some((ident, input)) = eat_identifier(input) { - let ident = String::from_utf8_lossy(ident).to_string(); + if let Some(ident) = eat_identifier(&input_tendril) { return ( - input, + ident.len(), Some(match &*ident { x if x.starts_with("aleo1") && x.chars().skip(5).all(|x| x.is_ascii_lowercase() || x.is_ascii_digit()) => { - Token::AddressLit(x.to_string()) + Token::AddressLit(ident) } "address" => Token::Address, "as" => Token::As, @@ -358,7 +344,7 @@ impl Token { ); } - (input, None) + (0, None) } } diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 6e307c7001..2cf32ccfc2 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -20,6 +20,8 @@ //! separated by whitespace. pub(crate) mod token; +use std::sync::Arc; + pub(crate) use self::token::*; pub(crate) mod lexer; @@ -27,31 +29,33 @@ pub(crate) use self::lexer::*; use crate::TokenError; use leo_ast::Span; - -use std::rc::Rc; +use tendril::StrTendril; /// Creates a new vector of spanned tokens from a given file path and source code text. -pub(crate) fn tokenize(path: &str, source: &str) -> Result, TokenError> { - let path = Rc::new(path.to_string()); - let mut input = source.as_bytes(); - let mut tokens = Vec::new(); +pub(crate) fn tokenize(path: &str, input: StrTendril) -> Result, TokenError> { + let path = Arc::new(path.to_string()); + let mut tokens = vec![]; let mut index = 0usize; let mut line_no = 1usize; let mut line_start = 0usize; - while !input.is_empty() { - match Token::gobble(input) { - (output, Some(token)) => { + while input.len() > index { + match Token::gobble(input.subtendril(index as u32, (input.len() - index) as u32)) { + (token_len, Some(token)) => { let mut span = Span { line_start: line_no, line_stop: line_no, col_start: index - line_start + 1, - col_stop: index - line_start + (input.len() - output.len()) + 1, + col_stop: index - line_start + token_len + 1, path: path.clone(), + content: input.subtendril( + line_start as u32, + input[line_start..].find('\n').unwrap_or(input.len() - line_start) as u32, + ), }; match &token { Token::CommentLine(_) => { line_no += 1; - line_start = index + (input.len() - output.len()); + line_start = index + token_len; } Token::CommentBlock(block) => { let line_ct = block.chars().filter(|x| *x == '\n').count(); @@ -59,7 +63,7 @@ pub(crate) fn tokenize(path: &str, source: &str) -> Result, To if line_ct > 0 { let last_line_index = block.rfind('\n').unwrap(); line_start = index + last_line_index + 1; - span.col_stop = index + (input.len() - output.len()) - line_start + 1; + span.col_stop = index + token_len - line_start + 1; } span.line_stop = line_no; } @@ -71,30 +75,32 @@ pub(crate) fn tokenize(path: &str, source: &str) -> Result, To _ => (), } tokens.push(SpannedToken { token, span }); - index += input.len() - output.len(); - input = output; + index += token_len; } - (output, None) => { - if output.is_empty() { + (token_len, None) => { + if token_len == 0 && index == input.len() { break; - } else if output.len() == input.len() { + } else if token_len == 0 { return Err(TokenError::unexpected_token( - &String::from_utf8_lossy(&[input[0]]), + &input[index..index + 1], &Span { line_start: line_no, line_stop: line_no, col_start: index - line_start + 1, col_stop: index - line_start + 2, path, + content: input.subtendril( + line_start as u32, + input[line_start..].find('\n').unwrap_or(input.len()) as u32, + ), }, )); } - index += input.len() - output.len(); - if input[0] == b'\n' { + if input.as_bytes()[index] == b'\n' { line_no += 1; - line_start = index; + line_start = index + token_len; } - input = output; + index += token_len; } } } @@ -212,18 +218,18 @@ mod tests { ? // test /* test */ - //"#, + //"# + .into(), ) .unwrap(); let mut output = String::new(); for SpannedToken { token, .. } in tokens.iter() { - output += &format!("{} ", &token.to_string()); + output += &format!("{} ", token.to_string()); } assert_eq!( output, r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= ? // test - /* test */ // - "# + /* test */ // "# ); } @@ -239,7 +245,7 @@ mod tests { test */ test "#; - let tokens = tokenize("test_path", raw).unwrap(); + let tokens = tokenize("test_path", raw.into()).unwrap(); let mut line_indicies = vec![0]; for (i, c) in raw.chars().enumerate() { if c == '\n' { diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index 18604d64db..88989b3c3d 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -16,11 +16,12 @@ use serde::{Deserialize, Serialize}; use std::fmt; +use tendril::StrTendril; /// Parts of a formatted string for logging to the console. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum FormattedStringPart { - Const(String), + Const(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), Container, } @@ -37,11 +38,11 @@ impl fmt::Display for FormattedStringPart { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Token { FormattedString(Vec), - AddressLit(String), - Ident(String), - Int(String), - CommentLine(String), - CommentBlock(String), + AddressLit(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), + Ident(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), + Int(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), + CommentLine(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), + CommentBlock(#[serde(with = "leo_ast::common::tendril_json")] StrTendril), Not, NotEq, And, @@ -193,7 +194,7 @@ impl fmt::Display for Token { AddressLit(s) => write!(f, "{}", s), Ident(s) => write!(f, "{}", s), Int(s) => write!(f, "{}", s), - CommentLine(s) => writeln!(f, "{}", s), + CommentLine(s) => write!(f, "{}", s), CommentBlock(s) => write!(f, "{}", s), Not => write!(f, "!"), NotEq => write!(f, "!="), diff --git a/parser/tests/serialization/expected_leo_ast.json b/parser/tests/serialization/expected_leo_ast.json index cedf6db8a0..cb4cff4c8c 100644 --- a/parser/tests/serialization/expected_leo_ast.json +++ b/parser/tests/serialization/expected_leo_ast.json @@ -4,9 +4,9 @@ "imports": [], "circuits": {}, "functions": { - "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"test\\\"}\"}": { + "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": { "annotations": [], - "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"test\\\"}\"}", + "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"test\\\",\\\"content\\\":\\\"function main() {\\\"}\"}", "input": [], "output": null, "block": { @@ -24,7 +24,8 @@ "line_stop": 2, "col_start": 12, "col_stop": 13, - "path": "test" + "path": "test", + "content": " return 1 + 1" } ] } @@ -38,7 +39,8 @@ "line_stop": 2, "col_start": 16, "col_stop": 17, - "path": "test" + "path": "test", + "content": " return 1 + 1" } ] } @@ -49,7 +51,8 @@ "line_stop": 2, "col_start": 12, "col_stop": 17, - "path": "test" + "path": "test", + "content": " return 1 + 1" } } }, @@ -58,7 +61,8 @@ "line_stop": 2, "col_start": 5, "col_stop": 17, - "path": "test" + "path": "test", + "content": " return 1 + 1" } } } @@ -68,7 +72,8 @@ "line_stop": 3, "col_start": 17, "col_stop": 2, - "path": "test" + "path": "test", + "content": "function main() {\n...\n}" } }, "span": { @@ -76,7 +81,8 @@ "line_stop": 3, "col_start": 1, "col_stop": 2, - "path": "test" + "path": "test", + "content": "function main() {\n...\n}" } } } diff --git a/state/src/utilities/input_value.rs b/state/src/utilities/input_value.rs index cdcf32feb1..a4e463f038 100644 --- a/state/src/utilities/input_value.rs +++ b/state/src/utilities/input_value.rs @@ -27,7 +27,7 @@ pub fn find_input( ) -> Result { let matched_parameter = parameters .iter() - .find(|(parameter, _value)| parameter.variable.name == name); + .find(|(parameter, _value)| parameter.variable.name.as_ref() == name); match matched_parameter { Some((_, Some(value))) => Ok(value.clone()), diff --git a/state/tests/test_verify_local_data_commitment.rs b/state/tests/test_verify_local_data_commitment.rs index f0a8e6b431..715dd47b8c 100644 --- a/state/tests/test_verify_local_data_commitment.rs +++ b/state/tests/test_verify_local_data_commitment.rs @@ -21,9 +21,7 @@ use leo_state::verify_local_data_commitment; use snarkvm_algorithms::traits::{CommitmentScheme, CRH}; use snarkvm_dpc::{ base_dpc::{instantiated::*, record_payload::RecordPayload, DPC}, - Account, - AccountScheme, - Record, + Account, AccountScheme, Record, }; use snarkvm_utilities::{bytes::ToBytes, to_bytes}; @@ -72,13 +70,11 @@ fn test_generate_values_from_dpc() { let noop_program_snark_pp = InstantiatedDPC::generate_noop_program_snark_parameters(&system_parameters, &mut rng).unwrap(); - let noop_program_id = to_bytes![ - ProgramVerificationKeyCRH::hash( - &system_parameters.program_verification_key_crh, - &to_bytes![noop_program_snark_pp.verification_key].unwrap() - ) - .unwrap() - ] + let noop_program_id = to_bytes![ProgramVerificationKeyCRH::hash( + &system_parameters.program_verification_key_crh, + &to_bytes![noop_program_snark_pp.verification_key].unwrap() + ) + .unwrap()] .unwrap(); let signature_parameters = &system_parameters.account_signature; From ee877be2a68a6091701cf86e4abff19d8298b776 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 22 Mar 2021 07:06:51 -0700 Subject: [PATCH 026/108] rebase --- parser/src/errors/syntax.rs | 7 +++++++ parser/src/parser/file.rs | 3 +++ 2 files changed, 10 insertions(+) diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index d2c31ac72a..5ee482fd38 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -89,4 +89,11 @@ impl SyntaxError { span, ) } + + pub fn illegal_self_const(span: &Span) -> Self { + Self::new_from_span( + "cannot have const self".to_string(), + span, + ) + } } diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index d767307343..f0b3a2e5b0 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -331,6 +331,9 @@ impl ParserContext { self.expect_ident()? }; if name.name.as_ref() == "self" { + if let Some(const_) = const_.as_ref() { + return Err(SyntaxError::illegal_self_const(&(&name.span + &const_.span))) + } if let Some(mutable) = &mutable { name.span = &mutable.span + &name.span; name.name = "mut self".to_string().into(); From daba572d945ef84e34852405f197d116bac28222 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 22 Mar 2021 09:41:52 -0700 Subject: [PATCH 027/108] clippy --- ast/src/common/vec_tendril_json.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ast/src/common/vec_tendril_json.rs b/ast/src/common/vec_tendril_json.rs index 27d7d02667..5a93b986f6 100644 --- a/ast/src/common/vec_tendril_json.rs +++ b/ast/src/common/vec_tendril_json.rs @@ -17,6 +17,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tendril::StrTendril; +#[allow(clippy::ptr_arg)] pub fn serialize(tendril: &Vec, serializer: S) -> Result { tendril .iter() From bbc6121f9d6690f7a5dbe94b9ff06a6ecde9e59f Mon Sep 17 00:00:00 2001 From: Protryon Date: Wed, 24 Mar 2021 10:17:54 -0700 Subject: [PATCH 028/108] clippy --- parser/src/tokenizer/lexer.rs | 2 +- parser/src/tokenizer/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index fe049bc093..2b1adb4cfe 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -25,7 +25,7 @@ use std::fmt; /// Returns a reference to bytes from the given input if the given string is equal to the bytes, /// otherwise returns [`None`]. /// -fn eat<'a>(input: &'a [u8], wanted: &str) -> Option { +fn eat(input: &[u8], wanted: &str) -> Option { let wanted = wanted.as_bytes(); if input.len() < wanted.len() { return None; diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 2cf32ccfc2..9452b483e2 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -91,7 +91,7 @@ pub(crate) fn tokenize(path: &str, input: StrTendril) -> Result Date: Fri, 26 Mar 2021 05:19:42 -0700 Subject: [PATCH 029/108] format --- asg/src/checks/return_path.rs | 9 +++++- asg/src/expression/call.rs | 15 +++++++-- asg/src/expression/circuit_access.rs | 15 +++++++-- asg/src/expression/circuit_init.rs | 15 +++++++-- asg/src/expression/constant.rs | 14 ++++++-- asg/src/expression/variable_ref.rs | 16 ++++++++-- asg/src/node.rs | 11 ++++++- asg/src/program/circuit.rs | 5 ++- asg/src/program/function.rs | 14 ++++++-- asg/src/statement/assign.rs | 18 +++++++++-- asg/src/statement/definition.rs | 14 ++++++-- asg/src/statement/iteration.rs | 11 ++++++- ast/src/common/identifier.rs | 8 +++-- ast/src/expression/mod.rs | 8 ++++- ast/src/groups/group_coordinate.rs | 7 ++-- ast/src/groups/group_value.rs | 4 ++- .../public_state/public_state.rs | 6 +--- ast/src/types/integer_type.rs | 3 +- ast/src/types/type_.rs | 5 ++- compiler/src/compiler.rs | 5 ++- compiler/src/console/assert.rs | 6 +++- compiler/src/errors/function.rs | 11 +++++-- compiler/src/expression/expression.rs | 3 +- .../src/function/input/main_function_input.rs | 4 ++- compiler/src/function/main_function.rs | 6 +++- compiler/src/function/mut_target.rs | 16 ++++++++-- compiler/src/function/result/result.rs | 6 +++- compiler/src/output/output_file.rs | 3 +- .../src/statement/conditional/conditional.rs | 8 +++-- compiler/src/statement/iteration/iteration.rs | 6 +++- compiler/src/value/address/address.rs | 6 +--- compiler/src/value/field/field_type.rs | 6 +--- .../src/value/group/targets/edwards_bls12.rs | 9 ++---- compiler/src/value/integer/macros.rs | 3 +- compiler/tests/array/mod.rs | 7 +++- compiler/tests/boolean/mod.rs | 7 +++- compiler/tests/console/mod.rs | 6 +++- .../core/packages/unstable/blake2s/mod.rs | 7 +++- compiler/tests/integers/i128/mod.rs | 5 ++- compiler/tests/integers/i16/mod.rs | 5 ++- compiler/tests/integers/i32/mod.rs | 5 ++- compiler/tests/integers/i64/mod.rs | 5 ++- compiler/tests/integers/i8/mod.rs | 5 ++- compiler/tests/integers/u128/mod.rs | 6 +++- compiler/tests/integers/u16/mod.rs | 6 +++- compiler/tests/integers/u32/mod.rs | 6 +++- compiler/tests/integers/u64/mod.rs | 6 +++- compiler/tests/integers/u8/mod.rs | 6 +++- compiler/tests/mod.rs | 5 ++- compiler/tests/statements/conditional/mod.rs | 10 ++++-- leo/api.rs | 3 +- leo/commands/package/clone.rs | 3 +- leo/config.rs | 4 ++- leo/main.rs | 25 ++++++++++----- leo/tests/mod.rs | 9 +++++- package/src/inputs/input.rs | 3 +- package/src/inputs/state.rs | 3 +- package/src/outputs/checksum.rs | 3 +- package/src/outputs/circuit.rs | 3 +- package/src/outputs/proof.rs | 3 +- package/src/outputs/proving_key.rs | 3 +- package/src/outputs/verification_key.rs | 3 +- package/src/root/zip.rs | 11 +++++-- package/tests/mod.rs | 3 +- parser/src/errors/syntax.rs | 5 +-- parser/src/parser/file.rs | 32 ++++++++----------- parser/src/tokenizer/mod.rs | 25 +++++++-------- .../test_verify_local_data_commitment.rs | 16 ++++++---- 68 files changed, 401 insertions(+), 149 deletions(-) diff --git a/asg/src/checks/return_path.rs b/asg/src/checks/return_path.rs index ae38417731..8a21f0514e 100644 --- a/asg/src/checks/return_path.rs +++ b/asg/src/checks/return_path.rs @@ -15,7 +15,14 @@ // along with the Leo library. If not, see . use crate::{ - statement::*, BoolAnd, Expression, Monoid, MonoidalReducerExpression, MonoidalReducerStatement, Node, Span, + statement::*, + BoolAnd, + Expression, + Monoid, + MonoidalReducerExpression, + MonoidalReducerStatement, + Node, + Span, }; pub struct ReturnPathReducer { diff --git a/asg/src/expression/call.rs b/asg/src/expression/call.rs index dfb3fbfaff..ada5458e5c 100644 --- a/asg/src/expression/call.rs +++ b/asg/src/expression/call.rs @@ -15,8 +15,19 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Function, FunctionQualifier, Node, - PartialType, Scope, Span, Type, + AsgConvertError, + CircuitMember, + ConstValue, + Expression, + ExpressionNode, + FromAst, + Function, + FunctionQualifier, + Node, + PartialType, + Scope, + Span, + Type, }; pub use leo_ast::{BinaryOperation, Node as AstNode}; diff --git a/asg/src/expression/circuit_access.rs b/asg/src/expression/circuit_access.rs index 42256682b1..6b45545860 100644 --- a/asg/src/expression/circuit_access.rs +++ b/asg/src/expression/circuit_access.rs @@ -15,8 +15,19 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, - PartialType, Scope, Span, Type, + AsgConvertError, + Circuit, + CircuitMember, + ConstValue, + Expression, + ExpressionNode, + FromAst, + Identifier, + Node, + PartialType, + Scope, + Span, + Type, }; use std::cell::Cell; diff --git a/asg/src/expression/circuit_init.rs b/asg/src/expression/circuit_init.rs index d14a3e91fb..a36fa5a43c 100644 --- a/asg/src/expression/circuit_init.rs +++ b/asg/src/expression/circuit_init.rs @@ -15,8 +15,19 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, Circuit, CircuitMember, ConstValue, Expression, ExpressionNode, FromAst, Identifier, Node, - PartialType, Scope, Span, Type, + AsgConvertError, + Circuit, + CircuitMember, + ConstValue, + Expression, + ExpressionNode, + FromAst, + Identifier, + Node, + PartialType, + Scope, + Span, + Type, }; use indexmap::{IndexMap, IndexSet}; diff --git a/asg/src/expression/constant.rs b/asg/src/expression/constant.rs index 1310596635..2f30d672dc 100644 --- a/asg/src/expression/constant.rs +++ b/asg/src/expression/constant.rs @@ -15,8 +15,18 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, GroupValue, Node, PartialType, Scope, - Span, Type, + AsgConvertError, + ConstInt, + ConstValue, + Expression, + ExpressionNode, + FromAst, + GroupValue, + Node, + PartialType, + Scope, + Span, + Type, }; use std::cell::Cell; diff --git a/asg/src/expression/variable_ref.rs b/asg/src/expression/variable_ref.rs index 349c93ccd4..b12363e38d 100644 --- a/asg/src/expression/variable_ref.rs +++ b/asg/src/expression/variable_ref.rs @@ -15,8 +15,20 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, ConstValue, Constant, DefinitionStatement, Expression, ExpressionNode, FromAst, Node, PartialType, - Scope, Span, Statement, Type, Variable, + AsgConvertError, + ConstValue, + Constant, + DefinitionStatement, + Expression, + ExpressionNode, + FromAst, + Node, + PartialType, + Scope, + Span, + Statement, + Type, + Variable, }; use std::cell::Cell; diff --git a/asg/src/node.rs b/asg/src/node.rs index 5b1b026802..58b4b7709e 100644 --- a/asg/src/node.rs +++ b/asg/src/node.rs @@ -15,7 +15,16 @@ // along with the Leo library. If not, see . use crate::{ - AsgContextInner, AsgConvertError, Circuit, Expression, Function, PartialType, Scope, Span, Statement, Variable, + AsgContextInner, + AsgConvertError, + Circuit, + Expression, + Function, + PartialType, + Scope, + Span, + Statement, + Variable, }; /// A node in the abstract semantic graph. diff --git a/asg/src/program/circuit.rs b/asg/src/program/circuit.rs index 18858840d9..4ef8bb57ff 100644 --- a/asg/src/program/circuit.rs +++ b/asg/src/program/circuit.rs @@ -111,7 +111,10 @@ impl<'a> Circuit<'a> { if asg_function.is_test() { return Err(AsgConvertError::circuit_test_function(&function.identifier.span)); } - members.insert(function.identifier.name.to_string(), CircuitMember::Function(asg_function)); + members.insert( + function.identifier.name.to_string(), + CircuitMember::Function(asg_function), + ); } } diff --git a/asg/src/program/function.rs b/asg/src/program/function.rs index 436570ab26..a594aa107d 100644 --- a/asg/src/program/function.rs +++ b/asg/src/program/function.rs @@ -15,8 +15,18 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, BlockStatement, Circuit, FromAst, Identifier, MonoidalDirector, ReturnPathReducer, Scope, Span, - Statement, Type, Variable, + AsgConvertError, + BlockStatement, + Circuit, + FromAst, + Identifier, + MonoidalDirector, + ReturnPathReducer, + Scope, + Span, + Statement, + Type, + Variable, }; use indexmap::IndexMap; pub use leo_ast::Annotation; diff --git a/asg/src/statement/assign.rs b/asg/src/statement/assign.rs index df9b525029..b2a23878b6 100644 --- a/asg/src/statement/assign.rs +++ b/asg/src/statement/assign.rs @@ -15,8 +15,22 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, CircuitMember, ConstInt, ConstValue, Expression, ExpressionNode, FromAst, Identifier, IntegerType, - Node, PartialType, Scope, Span, Statement, Type, Variable, + AsgConvertError, + CircuitMember, + ConstInt, + ConstValue, + Expression, + ExpressionNode, + FromAst, + Identifier, + IntegerType, + Node, + PartialType, + Scope, + Span, + Statement, + Type, + Variable, }; pub use leo_ast::AssignOperation; use leo_ast::AssigneeAccess as AstAssigneeAccess; diff --git a/asg/src/statement/definition.rs b/asg/src/statement/definition.rs index a835483cbe..1502f53244 100644 --- a/asg/src/statement/definition.rs +++ b/asg/src/statement/definition.rs @@ -15,8 +15,18 @@ // along with the Leo library. If not, see . use crate::{ - AsgConvertError, Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Span, Statement, - Type, Variable, + AsgConvertError, + Expression, + ExpressionNode, + FromAst, + InnerVariable, + Node, + PartialType, + Scope, + Span, + Statement, + Type, + Variable, }; use std::cell::{Cell, RefCell}; diff --git a/asg/src/statement/iteration.rs b/asg/src/statement/iteration.rs index 713d4d0ea9..e6d97ca0a2 100644 --- a/asg/src/statement/iteration.rs +++ b/asg/src/statement/iteration.rs @@ -17,7 +17,16 @@ use leo_ast::IntegerType; use crate::{ - AsgConvertError, Expression, ExpressionNode, FromAst, InnerVariable, Node, PartialType, Scope, Span, Statement, + AsgConvertError, + Expression, + ExpressionNode, + FromAst, + InnerVariable, + Node, + PartialType, + Scope, + Span, + Statement, Variable, }; diff --git a/ast/src/common/identifier.rs b/ast/src/common/identifier.rs index 6728212c77..f4a571bbb8 100644 --- a/ast/src/common/identifier.rs +++ b/ast/src/common/identifier.rs @@ -21,9 +21,13 @@ use tendril::StrTendril; use crate::Node; use serde::{ de::{ - Visitor, {self}, + Visitor, + {self}, }, - Deserialize, Deserializer, Serialize, Serializer, + Deserialize, + Deserializer, + Serialize, + Serializer, }; use std::{ collections::BTreeMap, diff --git a/ast/src/expression/mod.rs b/ast/src/expression/mod.rs index 2d2389d0ac..701efc50bc 100644 --- a/ast/src/expression/mod.rs +++ b/ast/src/expression/mod.rs @@ -15,7 +15,13 @@ // along with the Leo library. If not, see . use crate::{ - ArrayDimensions, CircuitImpliedVariableDefinition, GroupValue, Identifier, IntegerType, PositiveNumber, Span, + ArrayDimensions, + CircuitImpliedVariableDefinition, + GroupValue, + Identifier, + IntegerType, + PositiveNumber, + Span, SpreadOrExpression, }; diff --git a/ast/src/groups/group_coordinate.rs b/ast/src/groups/group_coordinate.rs index b8d05ee786..7f3e8a4666 100644 --- a/ast/src/groups/group_coordinate.rs +++ b/ast/src/groups/group_coordinate.rs @@ -16,8 +16,11 @@ use crate::common::span::Span; use leo_input::values::{ - GroupCoordinate as InputGroupCoordinate, Inferred as InputInferred, NumberValue as InputNumberValue, - SignHigh as InputSignHigh, SignLow as InputSignLow, + GroupCoordinate as InputGroupCoordinate, + Inferred as InputInferred, + NumberValue as InputNumberValue, + SignHigh as InputSignHigh, + SignLow as InputSignLow, }; use serde::{Deserialize, Serialize}; diff --git a/ast/src/groups/group_value.rs b/ast/src/groups/group_value.rs index e3bff066dc..f7e26069c7 100644 --- a/ast/src/groups/group_value.rs +++ b/ast/src/groups/group_value.rs @@ -16,7 +16,9 @@ use crate::{common::span::Span, groups::GroupCoordinate}; use leo_input::values::{ - GroupRepresentation as InputGroupRepresentation, GroupTuple as InputGroupTuple, GroupValue as InputGroupValue, + GroupRepresentation as InputGroupRepresentation, + GroupTuple as InputGroupTuple, + GroupValue as InputGroupValue, }; use serde::{Deserialize, Serialize}; diff --git a/ast/src/input/program_state/public_state/public_state.rs b/ast/src/input/program_state/public_state/public_state.rs index 7de8b04691..995aa06759 100644 --- a/ast/src/input/program_state/public_state/public_state.rs +++ b/ast/src/input/program_state/public_state/public_state.rs @@ -40,11 +40,7 @@ impl PublicState { } pub fn len(&self) -> usize { - if self.state.is_present() { - 1usize - } else { - 0usize - } + if self.state.is_present() { 1usize } else { 0usize } } /// Parse all input variables included in a file and store them in `self`. diff --git a/ast/src/types/integer_type.rs b/ast/src/types/integer_type.rs index a7768a3512..e2f3cab5bc 100644 --- a/ast/src/types/integer_type.rs +++ b/ast/src/types/integer_type.rs @@ -15,7 +15,8 @@ // along with the Leo library. If not, see . use leo_input::types::{ - IntegerType as InputIntegerType, SignedIntegerType as InputSignedIntegerType, + IntegerType as InputIntegerType, + SignedIntegerType as InputSignedIntegerType, UnsignedIntegerType as InputUnsignedIntegerType, }; diff --git a/ast/src/types/type_.rs b/ast/src/types/type_.rs index 9d6f6fd20e..f919ce8df2 100644 --- a/ast/src/types/type_.rs +++ b/ast/src/types/type_.rs @@ -16,7 +16,10 @@ use crate::{ArrayDimensions, Identifier, IntegerType}; use leo_input::types::{ - ArrayType as InputArrayType, DataType as InputDataType, TupleType as InputTupleType, Type as InputType, + ArrayType as InputArrayType, + DataType as InputDataType, + TupleType as InputTupleType, + Type as InputType, }; use serde::{Deserialize, Serialize}; diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 3088cc309c..0b19ea3b77 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -19,7 +19,10 @@ use crate::{ constraints::{generate_constraints, generate_test_constraints}, errors::CompilerError, - CompilerOptions, GroupType, OutputBytes, OutputFile, + CompilerOptions, + GroupType, + OutputBytes, + OutputFile, }; pub use leo_asg::{new_context, AsgContext as Context, AsgContext}; use leo_asg::{Asg, AsgPass, FormattedError, Program as AsgProgram}; diff --git a/compiler/src/console/assert.rs b/compiler/src/console/assert.rs index 1c616c53d3..d10658bc2a 100644 --- a/compiler/src/console/assert.rs +++ b/compiler/src/console/assert.rs @@ -17,7 +17,11 @@ //! Enforces an assert equals statement in a compiled Leo program. use crate::{ - errors::ConsoleError, get_indicator_value, program::ConstrainedProgram, value::ConstrainedValue, GroupType, + errors::ConsoleError, + get_indicator_value, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, }; use leo_asg::{Expression, Span}; diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index 9da4000513..791c654377 100644 --- a/compiler/src/errors/function.rs +++ b/compiler/src/errors/function.rs @@ -15,8 +15,15 @@ // along with the Leo library. If not, see . use crate::errors::{ - AddressError, BooleanError, ExpressionError, FieldError, GroupError, IntegerError, OutputBytesError, - StatementError, ValueError, + AddressError, + BooleanError, + ExpressionError, + FieldError, + GroupError, + IntegerError, + OutputBytesError, + StatementError, + ValueError, }; use leo_asg::AsgConvertError; use leo_ast::{FormattedError, LeoError, Span}; diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index 5377b591a5..dd966cab90 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -24,7 +24,8 @@ use crate::{ relational::*, resolve_core_circuit, value::{Address, ConstrainedValue, Integer}, - FieldType, GroupType, + FieldType, + GroupType, }; use leo_asg::{expression::*, ConstValue, Expression, Node, Span}; diff --git a/compiler/src/function/input/main_function_input.rs b/compiler/src/function/input/main_function_input.rs index abe2da156c..5eab3a9a7c 100644 --- a/compiler/src/function/input/main_function_input.rs +++ b/compiler/src/function/input/main_function_input.rs @@ -21,7 +21,9 @@ use crate::{ errors::FunctionError, program::ConstrainedProgram, value::{ - boolean::input::bool_from_input, field::input::field_from_input, group::input::group_from_input, + boolean::input::bool_from_input, + field::input::field_from_input, + group::input::group_from_input, ConstrainedValue, }, FieldType, diff --git a/compiler/src/function/main_function.rs b/compiler/src/function/main_function.rs index 8884be0e9f..5d4b738351 100644 --- a/compiler/src/function/main_function.rs +++ b/compiler/src/function/main_function.rs @@ -62,7 +62,11 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let input_variable = input_variable.get().borrow(); let name = input_variable.name.name.clone(); - let input_value = match (input_variable.const_, input.get(&name), input.get_constant(name.as_ref())) { + let input_value = match ( + input_variable.const_, + input.get(&name), + input.get_constant(name.as_ref()), + ) { // If variable is in both [main] and [constants] sections - error. (_, Some(_), Some(_)) => { return Err(FunctionError::double_input_declaration( diff --git a/compiler/src/function/mut_target.rs b/compiler/src/function/mut_target.rs index fd00543b67..913cd974ce 100644 --- a/compiler/src/function/mut_target.rs +++ b/compiler/src/function/mut_target.rs @@ -17,11 +17,21 @@ //! Resolves assignees in a compiled Leo program. use crate::{ - errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, ResolvedAssigneeAccess, + errors::StatementError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, + ResolvedAssigneeAccess, }; use leo_asg::{ - ArrayAccessExpression, ArrayRangeAccessExpression, CircuitAccessExpression, Expression, Node, Span, - TupleAccessExpression, Variable, + ArrayAccessExpression, + ArrayRangeAccessExpression, + CircuitAccessExpression, + Expression, + Node, + Span, + TupleAccessExpression, + Variable, }; use snarkvm_fields::PrimeField; diff --git a/compiler/src/function/result/result.rs b/compiler/src/function/result/result.rs index 1bff1822cc..f29669983d 100644 --- a/compiler/src/function/result/result.rs +++ b/compiler/src/function/result/result.rs @@ -17,7 +17,11 @@ //! Enforces that one return value is produced in a compiled Leo program. use crate::{ - errors::StatementError, get_indicator_value, program::ConstrainedProgram, value::ConstrainedValue, GroupType, + errors::StatementError, + get_indicator_value, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, }; use leo_asg::{Span, Type}; diff --git a/compiler/src/output/output_file.rs b/compiler/src/output/output_file.rs index e588f1909a..f9dd6eeda1 100644 --- a/compiler/src/output/output_file.rs +++ b/compiler/src/output/output_file.rs @@ -21,7 +21,8 @@ use crate::errors::OutputFileError; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/compiler/src/statement/conditional/conditional.rs b/compiler/src/statement/conditional/conditional.rs index c767d14293..5b86992414 100644 --- a/compiler/src/statement/conditional/conditional.rs +++ b/compiler/src/statement/conditional/conditional.rs @@ -17,8 +17,12 @@ //! Methods to enforce constraints on statements in a compiled Leo program. use crate::{ - errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, - IndicatorAndConstrainedValue, StatementResult, + errors::StatementError, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, + IndicatorAndConstrainedValue, + StatementResult, }; use leo_asg::ConditionalStatement; diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index 6b749ea419..0a2b3226af 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -17,7 +17,11 @@ //! Enforces an iteration statement in a compiled Leo program. use crate::{ - program::ConstrainedProgram, value::ConstrainedValue, GroupType, IndicatorAndConstrainedValue, Integer, + program::ConstrainedProgram, + value::ConstrainedValue, + GroupType, + IndicatorAndConstrainedValue, + Integer, StatementResult, }; use leo_asg::IterationStatement; diff --git a/compiler/src/value/address/address.rs b/compiler/src/value/address/address.rs index 1bcf1dff4b..fcd606f81b 100644 --- a/compiler/src/value/address/address.rs +++ b/compiler/src/value/address/address.rs @@ -198,11 +198,7 @@ impl ConditionalEqGadget for Address { } fn cond_select_helper(first: &Address, second: &Address, cond: bool) -> Address { - if cond { - first.clone() - } else { - second.clone() - } + if cond { first.clone() } else { second.clone() } } impl CondSelectGadget for Address { diff --git a/compiler/src/value/field/field_type.rs b/compiler/src/value/field/field_type.rs index d8afed1ff2..1280518aeb 100644 --- a/compiler/src/value/field/field_type.rs +++ b/compiler/src/value/field/field_type.rs @@ -289,11 +289,7 @@ impl CondSelectGadget for FieldType { second: &Self, ) -> Result { if let Boolean::Constant(cond) = *cond { - if cond { - Ok(first.clone()) - } else { - Ok(second.clone()) - } + if cond { Ok(first.clone()) } else { Ok(second.clone()) } } else { let first_gadget = first.allocated(&mut cs)?; let second_gadget = second.allocated(&mut cs)?; diff --git a/compiler/src/value/group/targets/edwards_bls12.rs b/compiler/src/value/group/targets/edwards_bls12.rs index 4bf55a017e..4b48511ef0 100644 --- a/compiler/src/value/group/targets/edwards_bls12.rs +++ b/compiler/src/value/group/targets/edwards_bls12.rs @@ -20,7 +20,8 @@ use leo_asg::{GroupCoordinate, GroupValue, Span}; use snarkvm_curves::{ edwards_bls12::{EdwardsAffine, EdwardsParameters, Fq}, templates::twisted_edwards_extended::GroupAffine, - AffineCurve, TEModelParameters, + AffineCurve, + TEModelParameters, }; use snarkvm_fields::{Fp256, One, Zero}; use snarkvm_gadgets::{ @@ -481,11 +482,7 @@ impl CondSelectGadget for EdwardsGroupType { second: &Self, ) -> Result { if let Boolean::Constant(cond) = *cond { - if cond { - Ok(first.clone()) - } else { - Ok(second.clone()) - } + if cond { Ok(first.clone()) } else { Ok(second.clone()) } } else { let first_gadget = first.allocated(cs.ns(|| "first"))?; let second_gadget = second.allocated(cs.ns(|| "second"))?; diff --git a/compiler/src/value/integer/macros.rs b/compiler/src/value/integer/macros.rs index de26e63e71..35f011d978 100644 --- a/compiler/src/value/integer/macros.rs +++ b/compiler/src/value/integer/macros.rs @@ -19,8 +19,7 @@ use snarkvm_gadgets::traits::utilities::{ int::{Int128, Int16, Int32, Int64, Int8}, uint::{UInt128, UInt16, UInt32, UInt64, UInt8}, }; -use std::convert::TryInto; -use std::fmt::Debug; +use std::{convert::TryInto, fmt::Debug}; pub trait IntegerTrait: Sized + Clone + Debug { fn get_value(&self) -> Option; diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index 4f57c064fe..fb01748d2f 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -15,7 +15,12 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, get_output, parse_program, parse_program_with_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + get_output, + parse_program, + parse_program_with_input, EdwardsTestCompiler, }; diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index 23d300c4cc..4051bf83d9 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -15,7 +15,12 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, get_output, parse_program, parse_program_with_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + get_output, + parse_program, + parse_program_with_input, EdwardsTestCompiler, }; diff --git a/compiler/tests/console/mod.rs b/compiler/tests/console/mod.rs index 0726ed148f..d3ce931675 100644 --- a/compiler/tests/console/mod.rs +++ b/compiler/tests/console/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, parse_program, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + parse_program, parse_program_with_input, }; use leo_ast::InputValue; diff --git a/compiler/tests/core/packages/unstable/blake2s/mod.rs b/compiler/tests/core/packages/unstable/blake2s/mod.rs index c0be4c09be..ce9a23b2f3 100644 --- a/compiler/tests/core/packages/unstable/blake2s/mod.rs +++ b/compiler/tests/core/packages/unstable/blake2s/mod.rs @@ -15,7 +15,12 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, generate_main_input, get_output, parse_program, parse_program_with_input, + assert_satisfied, + expect_asg_error, + generate_main_input, + get_output, + parse_program, + parse_program_with_input, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs index 2152b34b45..e62e07260e 100644 --- a/compiler/tests/integers/i128/mod.rs +++ b/compiler/tests/integers/i128/mod.rs @@ -15,7 +15,10 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs index 4b5b265979..49b45f5b3e 100644 --- a/compiler/tests/integers/i16/mod.rs +++ b/compiler/tests/integers/i16/mod.rs @@ -15,7 +15,10 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs index 0589f2e3e4..ee9e25701a 100644 --- a/compiler/tests/integers/i32/mod.rs +++ b/compiler/tests/integers/i32/mod.rs @@ -15,7 +15,10 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs index 9ac964b71f..066ac9956f 100644 --- a/compiler/tests/integers/i64/mod.rs +++ b/compiler/tests/integers/i64/mod.rs @@ -15,7 +15,10 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs index 5114e91a32..9133a72248 100644 --- a/compiler/tests/integers/i8/mod.rs +++ b/compiler/tests/integers/i8/mod.rs @@ -15,7 +15,10 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, integers::{expect_computation_error, IntegerTester}, parse_program, }; diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 984930776e..2c110af0a5 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index 9ac9c2c48a..b4b202b9da 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index f1ccc0588d..920fc6ed5b 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index 7a21e5c0e4..ec86c868f1 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index c328b75e07..a61e28246d 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -15,7 +15,11 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_asg_error, expect_compiler_error, generate_main_input, integers::IntegerTester, + assert_satisfied, + expect_asg_error, + expect_compiler_error, + generate_main_input, + integers::IntegerTester, parse_program, }; use leo_ast::InputValue; diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index 9f8a03bc1e..96069ffe54 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -41,7 +41,10 @@ pub mod tuples; use leo_asg::{new_alloc_context, new_context, AsgContext}; use leo_ast::{InputValue, MainInput}; use leo_compiler::{ - compiler::Compiler, errors::CompilerError, group::targets::edwards_bls12::EdwardsGroupType, ConstrainedValue, + compiler::Compiler, + errors::CompilerError, + group::targets::edwards_bls12::EdwardsGroupType, + ConstrainedValue, OutputBytes, }; use leo_input::types::{IntegerType, U32Type, UnsignedIntegerType}; diff --git a/compiler/tests/statements/conditional/mod.rs b/compiler/tests/statements/conditional/mod.rs index 30c9180e92..c57f7974de 100644 --- a/compiler/tests/statements/conditional/mod.rs +++ b/compiler/tests/statements/conditional/mod.rs @@ -15,8 +15,14 @@ // along with the Leo library. If not, see . use crate::{ - assert_satisfied, expect_compiler_error, generate_main_input, generate_test_input_u32, get_output, parse_program, - parse_program_with_input, EdwardsTestCompiler, + assert_satisfied, + expect_compiler_error, + generate_main_input, + generate_test_input_u32, + get_output, + parse_program, + parse_program_with_input, + EdwardsTestCompiler, }; use leo_ast::InputValue; diff --git a/leo/api.rs b/leo/api.rs index 5cd384479b..23e12b3578 100644 --- a/leo/api.rs +++ b/leo/api.rs @@ -17,7 +17,8 @@ use anyhow::{anyhow, Error, Result}; use reqwest::{ blocking::{Client, Response}, - Method, StatusCode, + Method, + StatusCode, }; use serde::Serialize; diff --git a/leo/commands/package/clone.rs b/leo/commands/package/clone.rs index c899cbe046..5b5e6acdcf 100644 --- a/leo/commands/package/clone.rs +++ b/leo/commands/package/clone.rs @@ -20,7 +20,8 @@ use anyhow::{anyhow, Result}; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::{Read, Write}, path::Path, diff --git a/leo/config.rs b/leo/config.rs index 848533f05b..11de847b70 100644 --- a/leo/config.rs +++ b/leo/config.rs @@ -16,7 +16,9 @@ use std::{ fs::{ - create_dir_all, File, {self}, + create_dir_all, + File, + {self}, }, io, io::prelude::*, diff --git a/leo/main.rs b/leo/main.rs index 81dc979e9e..a0d256230c 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -23,7 +23,19 @@ pub mod updater; use commands::{ package::{Add, Clone, Login, Logout, Publish, Remove}, - Build, Clean, Command, Deploy, Init, Lint, New, Prove, Run, Setup, Test, Update, Watch, + Build, + Clean, + Command, + Deploy, + Init, + Lint, + New, + Prove, + Run, + Setup, + Test, + Update, + Watch, }; use anyhow::Error; @@ -163,13 +175,10 @@ fn main() { if !opt.quiet { // init logger with optional debug flag - logger::init_logger( - "leo", - match opt.debug { - false => 1, - true => 2, - }, - ); + logger::init_logger("leo", match opt.debug { + false => 1, + true => 2, + }); } handle_error(match opt.command { diff --git a/leo/tests/mod.rs b/leo/tests/mod.rs index 9607594e4f..7bc611f49d 100644 --- a/leo/tests/mod.rs +++ b/leo/tests/mod.rs @@ -21,7 +21,14 @@ use anyhow::Result; use crate::{ commands::{ package::{Login, Logout}, - Build, Command, Prove, Run, Setup, Test, Update, UpdateAutomatic, + Build, + Command, + Prove, + Run, + Setup, + Test, + Update, + UpdateAutomatic, }, context::{create_context, Context}, }; diff --git a/package/src/inputs/input.rs b/package/src/inputs/input.rs index 74ca67484a..3e01cbbe5d 100644 --- a/package/src/inputs/input.rs +++ b/package/src/inputs/input.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/inputs/state.rs b/package/src/inputs/state.rs index 4c7994291e..7bda80ceb7 100644 --- a/package/src/inputs/state.rs +++ b/package/src/inputs/state.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/checksum.rs b/package/src/outputs/checksum.rs index 3f56c22a76..9352429973 100644 --- a/package/src/outputs/checksum.rs +++ b/package/src/outputs/checksum.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/circuit.rs b/package/src/outputs/circuit.rs index 81a528f310..d9d0e8cced 100644 --- a/package/src/outputs/circuit.rs +++ b/package/src/outputs/circuit.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/proof.rs b/package/src/outputs/proof.rs index 6a9419b889..815d6048be 100644 --- a/package/src/outputs/proof.rs +++ b/package/src/outputs/proof.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/proving_key.rs b/package/src/outputs/proving_key.rs index 35f054554d..7e2d938bd7 100644 --- a/package/src/outputs/proving_key.rs +++ b/package/src/outputs/proving_key.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/outputs/verification_key.rs b/package/src/outputs/verification_key.rs index 9acfe62fc4..6f7fca8797 100644 --- a/package/src/outputs/verification_key.rs +++ b/package/src/outputs/verification_key.rs @@ -22,7 +22,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::Write, path::Path, diff --git a/package/src/root/zip.rs b/package/src/root/zip.rs index a377e263c5..46426b9d3e 100644 --- a/package/src/root/zip.rs +++ b/package/src/root/zip.rs @@ -21,8 +21,12 @@ use crate::{ imports::IMPORTS_DIRECTORY_NAME, inputs::{INPUTS_DIRECTORY_NAME, INPUT_FILE_EXTENSION, STATE_FILE_EXTENSION}, outputs::{ - CHECKSUM_FILE_EXTENSION, CIRCUIT_FILE_EXTENSION, OUTPUTS_DIRECTORY_NAME, PROOF_FILE_EXTENSION, - PROVING_KEY_FILE_EXTENSION, VERIFICATION_KEY_FILE_EXTENSION, + CHECKSUM_FILE_EXTENSION, + CIRCUIT_FILE_EXTENSION, + OUTPUTS_DIRECTORY_NAME, + PROOF_FILE_EXTENSION, + PROVING_KEY_FILE_EXTENSION, + VERIFICATION_KEY_FILE_EXTENSION, }, root::{MANIFEST_FILENAME, README_FILENAME}, source::{SOURCE_DIRECTORY_NAME, SOURCE_FILE_EXTENSION}, @@ -32,7 +36,8 @@ use serde::Deserialize; use std::{ borrow::Cow, fs::{ - File, {self}, + File, + {self}, }, io::{Read, Write}, path::Path, diff --git a/package/tests/mod.rs b/package/tests/mod.rs index c04bfade1f..8f72a16b3e 100644 --- a/package/tests/mod.rs +++ b/package/tests/mod.rs @@ -22,7 +22,8 @@ pub mod manifest; use lazy_static::lazy_static; use std::{ cell::RefCell, - env, fs, + env, + fs, path::PathBuf, sync::atomic::{AtomicUsize, Ordering}, }; diff --git a/parser/src/errors/syntax.rs b/parser/src/errors/syntax.rs index 5ee482fd38..ca73d75f0b 100644 --- a/parser/src/errors/syntax.rs +++ b/parser/src/errors/syntax.rs @@ -91,9 +91,6 @@ impl SyntaxError { } pub fn illegal_self_const(span: &Span) -> Self { - Self::new_from_span( - "cannot have const self".to_string(), - span, - ) + Self::new_from_span("cannot have const self".to_string(), span) } } diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index f0b3a2e5b0..11279d06bf 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -299,13 +299,10 @@ impl ParserContext { let member = self.parse_circuit_member()?; members.push(member); } - Ok(( - name.clone(), - Circuit { - circuit_name: name, - members, - }, - )) + Ok((name.clone(), Circuit { + circuit_name: name, + members, + })) } /// @@ -332,7 +329,7 @@ impl ParserContext { }; if name.name.as_ref() == "self" { if let Some(const_) = const_.as_ref() { - return Err(SyntaxError::illegal_self_const(&(&name.span + &const_.span))) + return Err(SyntaxError::illegal_self_const(&(&name.span + &const_.span))); } if let Some(mutable) = &mutable { name.span = &mutable.span + &name.span; @@ -390,16 +387,13 @@ impl ParserContext { None }; let block = self.parse_block()?; - Ok(( - name.clone(), - Function { - annotations, - identifier: name, - input: inputs, - output, - span: start + block.span.clone(), - block, - }, - )) + Ok((name.clone(), Function { + annotations, + identifier: name, + input: inputs, + output, + span: start + block.span.clone(), + block, + })) } } diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 9452b483e2..fb64f4222a 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -81,20 +81,17 @@ pub(crate) fn tokenize(path: &str, input: StrTendril) -> Result Date: Fri, 26 Mar 2021 18:41:24 +0300 Subject: [PATCH 030/108] adds grammar binary package for markdown conversion --- Cargo.lock | 97 ++++++++++++++++++- Cargo.toml | 1 + grammar/Cargo.toml | 12 +++ grammar/src/main.rs | 224 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 grammar/Cargo.toml create mode 100644 grammar/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index c67dfafaf7..8d8d160ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,25 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "abnf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020babd9b431b239cffff9eb1e49d8cad5f3581674d3938540801e633a3b5f69" +dependencies = [ + "abnf-core", + "nom 6.1.2", +] + +[[package]] +name = "abnf-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b514944cb7199c4201f54406bc58676a3e4f37d40bf8e3dbe30652ca82e3ddb4" +dependencies = [ + "nom 6.1.2", +] + [[package]] name = "addr2line" version = "0.14.1" @@ -157,6 +176,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake2" version = "0.9.1" @@ -290,7 +321,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom", + "nom 5.1.2", ] [[package]] @@ -787,6 +818,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "futures-channel" version = "0.3.13" @@ -906,6 +943,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "grammar" +version = "0.1.0" +dependencies = [ + "abnf", + "anyhow", +] + [[package]] name = "h2" version = "0.3.1" @@ -1384,6 +1429,19 @@ dependencies = [ "snarkvm-r1cs", ] +[[package]] +name = "lexical-core" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.89" @@ -1624,6 +1682,19 @@ dependencies = [ "version_check", ] +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "notify" version = "4.0.15" @@ -2009,6 +2080,12 @@ dependencies = [ "proc-macro2 1.0.24", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.8.3" @@ -2673,6 +2750,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.8.0" @@ -2743,6 +2826,12 @@ dependencies = [ "unicode-xid 0.2.1", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.2.0" @@ -3271,6 +3360,12 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "zip" version = "0.5.11" diff --git a/Cargo.toml b/Cargo.toml index e724a38295..38dc4f2418 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "asg", "ast", "compiler", + "grammar", "imports", "input", "linter", diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml new file mode 100644 index 0000000000..1af9c39313 --- /dev/null +++ b/grammar/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "grammar" +version = "0.1.0" +authors = [ "The Aleo Team " ] +description = "ABNF to Markdown converter" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +abnf = "0.10.0" +anyhow = "1.0" diff --git a/grammar/src/main.rs b/grammar/src/main.rs new file mode 100644 index 0000000000..defb8ce9ef --- /dev/null +++ b/grammar/src/main.rs @@ -0,0 +1,224 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +// ABNF PARSING RULES +// +// Header: +// ```abnf +// ; Introduction +// ; ------------- +// ``` +// +// Code block in docs (note double whitespace after colon): +// ```abnf +// ; code +// ; code +//``` +// +// Rule: +// ```abnf +// address = "address" +// ``` +// +// Line: +// ``` abnf +// ;;;;;;;;; +// ``` +// +use abnf::types::{Node, Rule}; +use anyhow::Result; +use std::collections::{HashMap, HashSet}; + +/// Processor's scope. Used when code block or definition starts or ends. +#[derive(Debug, Clone)] +enum Scope { + Free, + Code, + Definition(Rule), +} + +/// Transforms abnf file into Markdown. +#[derive(Debug, Clone)] +struct Processor<'a> { + rules: HashMap, + grammar: &'a str, + scope: Scope, + line: u32, + out: String, +} + +impl<'a> Processor<'a> { + fn new(grammar: &'a str, abnf: Vec) -> Processor<'a> { + // we need a hashmap to pull rules easily + let rules: HashMap = abnf.into_iter().map(|rule| (rule.name().to_string(), rule)).collect(); + + Processor { + grammar, + line: 0, + out: String::new(), + rules, + scope: Scope::Free, + } + } + + /// Main function for this struct. + /// Goes through each line and transforms it into proper markdown. + fn process(&mut self) -> Result<()> { + let mut lines = self.grammar.lines(); + let mut prev = ""; + + while let Some(line) = lines.next() { + self.line += 1; + + // code block in comment (not highlighted as abnf) + if line.starts_with("; ") { + self.enter_scope(Scope::Code)?; + self.append_str(&line[3..]); + + // just comment. end of code block + } else if line.starts_with("; ") { + self.enter_scope(Scope::Free)?; + self.append_str(&line[2..]); + + // horizontal rule - section separator + } else if line.starts_with(";;;;;;;;;;") { + self.enter_scope(Scope::Free)?; + self.append_str("\n--------\n"); + + // empty line in comment. end of code block + } else if line.starts_with(";") { + self.enter_scope(Scope::Free)?; + self.append_str("\n\n"); + + // just empty line. end of doc, start of definition + } else if line.len() == 0 { + self.enter_scope(Scope::Free)?; + self.append_str(""); + + // definition (may be multiline) + } else { + // if there's an equality sign and previous line was empty + if line.contains("=") && prev.len() == 0 { + let (def, _) = line.split_at(line.find("=").unwrap()); + let def = def.trim(); + + // try to find rule matching definition or fail + let rule = self.rules.get(&def.to_string()).map(|rule| rule.clone()).unwrap(); + + self.enter_scope(Scope::Definition(rule))?; + } + + self.append_str(line); + } + + prev = line; + } + + Ok(()) + } + + /// Append new line into output, add newline character. + fn append_str(&mut self, line: &str) { + self.out.push_str(line); + self.out.push_str("\n"); + } + + /// Enter new scope (definition or code block). Allows customizing + /// pre and post lines for each scope entered or exited. + fn enter_scope(&mut self, new_scope: Scope) -> Result<()> { + match (&self.scope, &new_scope) { + // exchange scopes between Free and Code + (Scope::Free, Scope::Code) => self.append_str("```"), + (Scope::Code, Scope::Free) => self.append_str("```"), + // exchange scopes between Free and Definition + (Scope::Free, Scope::Definition(rule)) => { + self.append_str(&format!("", rule.name())); + self.append_str("```abnf"); + } + (Scope::Definition(rule), Scope::Free) => { + let mut rules: Vec = Vec::new(); + parse_abnf_node(rule.node(), &mut rules); + + // 1. leave only unique keys + // 2. map each rule into a link + // 3. join results as a list + // Note: GitHub only allows custom tags with 'user-content-' prefix + let keys = rules + .into_iter() + .collect::>() + .into_iter() + .map(|tag| format!("[{}](#user-content-{})", &tag, tag)) + .collect::>() + .join(", "); + + self.append_str("```"); + + if keys.len() > 0 { + self.append_str(&format!("\nGo to: _{}_;\n", keys)); + } + } + (_, _) => (), + }; + + self.scope = new_scope; + + Ok(()) + } +} + +/// Recursively parse ABNF Node and fill sum vec with found rule names. +fn parse_abnf_node(node: &Node, sum: &mut Vec) { + match node { + // these two are just vectors of rules + Node::Alternation(vec) | Node::Concatenation(vec) => { + for node in vec { + parse_abnf_node(node, sum); + } + } + Node::Group(node) | Node::Optional(node) => parse_abnf_node(node.as_ref(), sum), + + // push rulename if it is known + Node::Rulename(name) => sum.push(name.clone()), + + // do nothing for other nodes + _ => (), + } +} + +fn main() -> Result<()> { + // Take Leo ABNF grammar file. + let grammar = include_str!("../abnf-grammar.txt"); + + // A. Coglio's proposal for %s syntax for case-sensitive statements has not been implemented + // in this library, so we need to remove all occurrences of %s in the grammar file. + // Link to this proposal: https://www.kestrel.edu/people/coglio/vstte18.pdf + let grammar = &str::replace(grammar, "%s", ""); + + // Parse ABNF to get list of all definitions. + let parsed = abnf::rulelist(grammar).map_err(|e| { + eprintln!("{}", &e); + anyhow::anyhow!(e) + })?; + + // Init parser and run it. That's it. + let mut parser = Processor::new(grammar, parsed); + parser.process()?; + + // Print result of conversion to STDOUT. + println!("{}", parser.out); + + Ok(()) +} From 60f5a91bd994c4ebe8e5beccbd18cfdaf76fe045 Mon Sep 17 00:00:00 2001 From: damirka Date: Fri, 26 Mar 2021 18:50:11 +0300 Subject: [PATCH 031/108] changes grammar to leo-abnf, adds keywords and version --- Cargo.lock | 16 ++++++++-------- grammar/Cargo.toml | 14 ++++++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d8d160ccf..38e378188b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -943,14 +943,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -[[package]] -name = "grammar" -version = "0.1.0" -dependencies = [ - "abnf", - "anyhow", -] - [[package]] name = "h2" version = "0.3.1" @@ -1236,6 +1228,14 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leo-abnf" +version = "1.2.3" +dependencies = [ + "abnf", + "anyhow", +] + [[package]] name = "leo-asg" version = "1.2.3" diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index 1af9c39313..e9dcc5a044 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -1,11 +1,17 @@ [package] -name = "grammar" -version = "0.1.0" +name = "leo-abnf" +version = "1.2.3" authors = [ "The Aleo Team " ] description = "ABNF to Markdown converter" edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +keywords = [ + "aleo", + "cryptography", + "leo", + "programming-language", + "zero-knowledge", + "leo-abnf" +] [dependencies] abnf = "0.10.0" From 78b4f39b5aa3f7bcefff2a9e60a0d86238156192 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 26 Mar 2021 12:27:35 -0400 Subject: [PATCH 032/108] fix master merge --- parser/src/parser/expression.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index ed07e1a7c8..0f4e6e56af 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -309,7 +309,7 @@ impl ParserContext { /// Otherwise, tries to parse the next token using [`parse_cast_expression`]. /// pub fn parse_exponential_expression(&mut self) -> SyntaxResult { - let mut exprs = vec![self.parse_cast_expression()?]; + let mut exprs = vec![]; exprs.push(self.parse_cast_expression()?); while self.eat(Token::Exp).is_some() { exprs.push(self.parse_cast_expression()?); From 871e52006bf690b98363c0592fc1c84bf85f8efc Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 26 Mar 2021 16:51:03 -0400 Subject: [PATCH 033/108] quick bug fix --- ast/src/reducer/canonicalization.rs | 23 ++++++++++++++++++- .../canonicalization/compound_assignment.leo | 9 ++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ast/src/reducer/canonicalization.rs b/ast/src/reducer/canonicalization.rs index e9be54f691..fdf14af4e8 100644 --- a/ast/src/reducer/canonicalization.rs +++ b/ast/src/reducer/canonicalization.rs @@ -470,7 +470,28 @@ impl ReconstructingReducer for Canonicalizer { ) -> Result { match value { Expression::Value(value_expr) if assign.operation != AssignOperation::Assign => { - let left = Box::new(Expression::Identifier(assignee.identifier.clone())); + let mut left = Box::new(Expression::Identifier(assignee.identifier.clone())); + + for access in assignee.accesses.iter().rev() { + match self.canonicalize_assignee_access(&access) { + AssigneeAccess::ArrayIndex(index) => { + left = Box::new(Expression::ArrayAccess(ArrayAccessExpression { + array: left, + index: Box::new(index), + span: assign.span.clone(), + })); + } + AssigneeAccess::Tuple(positive_number, _) => { + left = Box::new(Expression::TupleAccess(TupleAccessExpression { + tuple: left, + index: positive_number, + span: assign.span.clone(), + })); + } + _ => {} + } + } + let right = Box::new(Expression::Value(value_expr)); let op = match assign.operation { diff --git a/compiler/tests/canonicalization/compound_assignment.leo b/compiler/tests/canonicalization/compound_assignment.leo index 95c810a7d5..6f4b9834ae 100644 --- a/compiler/tests/canonicalization/compound_assignment.leo +++ b/compiler/tests/canonicalization/compound_assignment.leo @@ -1,4 +1,13 @@ function main() { let x = 10u32; x += 20; + console.assert(x == 30u32); + + let y = [1u8, 2u8]; + y[0] += 3u8; + console.assert(y[0] == 4u8); + + let z = (1u8, 2u8); + z.1 += 3u8; + console.assert(z.1 == 5u8); } \ No newline at end of file From 3e912ef165e831fdcb42128eb19e34d947be6ec2 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 26 Mar 2021 17:02:59 -0400 Subject: [PATCH 034/108] access member fix --- ast/src/reducer/canonicalization.rs | 9 ++++++++- compiler/tests/canonicalization/compound_assignment.leo | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ast/src/reducer/canonicalization.rs b/ast/src/reducer/canonicalization.rs index fdf14af4e8..e8bf413fdc 100644 --- a/ast/src/reducer/canonicalization.rs +++ b/ast/src/reducer/canonicalization.rs @@ -488,7 +488,14 @@ impl ReconstructingReducer for Canonicalizer { span: assign.span.clone(), })); } - _ => {} + AssigneeAccess::Member(identifier) => { + left = Box::new(Expression::CircuitMemberAccess(CircuitMemberAccessExpression { + circuit: left, + name: identifier, + span: assign.span.clone(), + })); + } + _ => unimplemented!(), // No reason for someone to comput ArrayRanges. } } diff --git a/compiler/tests/canonicalization/compound_assignment.leo b/compiler/tests/canonicalization/compound_assignment.leo index 6f4b9834ae..c7a633c9a4 100644 --- a/compiler/tests/canonicalization/compound_assignment.leo +++ b/compiler/tests/canonicalization/compound_assignment.leo @@ -1,3 +1,6 @@ +circuit Foo { + f: u8, +} function main() { let x = 10u32; x += 20; @@ -10,4 +13,8 @@ function main() { let z = (1u8, 2u8); z.1 += 3u8; console.assert(z.1 == 5u8); + + let foo = Foo { f: 6u8 }; + foo.f = foo.f + 2u8; + console.assert(foo.f == 8u8); } \ No newline at end of file From dadb518598d209acd3b995b0074f59d99ad99a34 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 26 Mar 2021 17:14:37 -0400 Subject: [PATCH 035/108] forgot to update test json --- ast/src/reducer/canonicalization.rs | 2 +- .../canonicalization/compound_assignment.json | 870 ++++++++++++++++-- 2 files changed, 777 insertions(+), 95 deletions(-) diff --git a/ast/src/reducer/canonicalization.rs b/ast/src/reducer/canonicalization.rs index e8bf413fdc..7bf1b12b88 100644 --- a/ast/src/reducer/canonicalization.rs +++ b/ast/src/reducer/canonicalization.rs @@ -495,7 +495,7 @@ impl ReconstructingReducer for Canonicalizer { span: assign.span.clone(), })); } - _ => unimplemented!(), // No reason for someone to comput ArrayRanges. + _ => unimplemented!(), // No reason for someone to compute ArrayRanges. } } diff --git a/compiler/tests/canonicalization/compound_assignment.json b/compiler/tests/canonicalization/compound_assignment.json index fda6fb09cf..7e2d4fab90 100644 --- a/compiler/tests/canonicalization/compound_assignment.json +++ b/compiler/tests/canonicalization/compound_assignment.json @@ -1,128 +1,810 @@ { - "name": "", - "expected_input": [], - "imports": [], - "circuits": {}, - "functions": { - "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": { - "annotations": [], - "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}", - "input": [], - "output": { - "Tuple": [] - }, - "block": { - "statements": [ + "name": "", + "expected_input": [], + "imports": [], + "circuits": { + "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}": { + "circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", + "members": [ + { + "CircuitVariable": [ + "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}", { - "Definition": { - "declaration_type": "Let", - "variable_names": [ - { - "mutable": true, - "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":11,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", - "span": { - "line_start": 2, - "line_stop": 2, - "col_start": 7, - "col_stop": 12, - "path": "" - } - } - ], - "type_": null, - "value": { - "Value": { - "Integer": [ - "U32", - "10", - { - "line_start": 2, - "line_stop": 2, - "col_start": 15, - "col_stop": 20, - "path": "" - } - ] - } - }, - "span": { - "line_start": 2, - "line_stop": 2, - "col_start": 3, - "col_stop": 20, - "path": "" - } - } - }, - { - "Assign": { - "operation": "Assign", - "assignee": { - "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}", - "accesses": [], + "IntegerType": "U8" + } + ] + } + ] + } + }, + "functions": { + "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": { + "annotations": [], + "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}", + "input": [], + "output": { + "Tuple": [] + }, + "block": { + "statements": [ + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}", "span": { - "line_start": 3, - "line_stop": 3, - "col_start": 3, - "col_stop": 4, + "line_start": 5, + "line_stop": 5, + "col_start": 9, + "col_stop": 10, "path": "" } - }, - "value": { + } + ], + "type_": null, + "value": { + "Value": { + "Integer": [ + "U32", + "10", + { + "line_start": 5, + "line_stop": 5, + "col_start": 13, + "col_stop": 18, + "path": "" + } + ] + } + }, + "span": { + "line_start": 5, + "line_stop": 5, + "col_start": 5, + "col_stop": 18, + "path": "" + } + } + }, + { + "Assign": { + "operation": "Assign", + "assignee": { + "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}", + "accesses": [], + "span": { + "line_start": 6, + "line_stop": 6, + "col_start": 5, + "col_stop": 6, + "path": "" + } + }, + "value": { + "Binary": { + "left": { + "Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}" + }, + "right": { + "Value": { + "Implicit": [ + "20", + { + "line_start": 6, + "line_stop": 6, + "col_start": 10, + "col_stop": 12, + "path": "" + } + ] + } + }, + "op": "Add", + "span": { + "line_start": 6, + "line_stop": 6, + "col_start": 5, + "col_stop": 12, + "path": "" + } + } + }, + "span": { + "line_start": 6, + "line_stop": 6, + "col_start": 5, + "col_stop": 12, + "path": "" + } + } + }, + { + "Console": { + "function": { + "Assert": { "Binary": { "left": { - "Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}" + "Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":7,\\\"line_stop\\\":7,\\\"col_start\\\":20,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}" }, "right": { "Value": { - "Implicit": [ - "20", + "Integer": [ + "U32", + "30", { - "line_start": 3, - "line_stop": 3, - "col_start": 8, - "col_stop": 10, + "line_start": 7, + "line_stop": 7, + "col_start": 25, + "col_stop": 30, "path": "" } ] } }, - "op": "Add", + "op": "Eq", "span": { - "line_start": 3, - "line_stop": 3, - "col_start": 3, - "col_stop": 10, + "line_start": 7, + "line_stop": 7, + "col_start": 20, + "col_stop": 30, "path": "" } } - }, + } + }, + "span": { + "line_start": 7, + "line_stop": 7, + "col_start": 5, + "col_stop": 30, + "path": "" + } + } + }, + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}", + "span": { + "line_start": 9, + "line_stop": 9, + "col_start": 9, + "col_stop": 10, + "path": "" + } + } + ], + "type_": null, + "value": { + "ArrayInline": { + "elements": [ + { + "Expression": { + "Value": { + "Integer": [ + "U8", + "1", + { + "line_start": 9, + "line_stop": 9, + "col_start": 14, + "col_stop": 17, + "path": "" + } + ] + } + } + }, + { + "Expression": { + "Value": { + "Integer": [ + "U8", + "2", + { + "line_start": 9, + "line_stop": 9, + "col_start": 19, + "col_stop": 22, + "path": "" + } + ] + } + } + } + ], + "span": { + "line_start": 9, + "line_stop": 9, + "col_start": 13, + "col_stop": 23, + "path": "" + } + } + }, + "span": { + "line_start": 9, + "line_stop": 9, + "col_start": 5, + "col_stop": 23, + "path": "" + } + } + }, + { + "Assign": { + "operation": "Assign", + "assignee": { + "identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":10,\\\"line_stop\\\":10,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}", + "accesses": [ + { + "ArrayIndex": { + "Value": { + "Implicit": [ + "0", + { + "line_start": 10, + "line_stop": 10, + "col_start": 7, + "col_stop": 8, + "path": "" + } + ] + } + } + } + ], "span": { - "line_start": 3, - "line_stop": 3, - "col_start": 3, + "line_start": 10, + "line_stop": 10, + "col_start": 5, + "col_stop": 9, + "path": "" + } + }, + "value": { + "Binary": { + "left": { + "ArrayAccess": { + "array": { + "Identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":10,\\\"line_stop\\\":10,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}" + }, + "index": { + "Value": { + "Implicit": [ + "0", + { + "line_start": 10, + "line_stop": 10, + "col_start": 7, + "col_stop": 8, + "path": "" + } + ] + } + }, + "span": { + "line_start": 10, + "line_stop": 10, + "col_start": 5, + "col_stop": 16, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "3", + { + "line_start": 10, + "line_stop": 10, + "col_start": 13, + "col_stop": 16, + "path": "" + } + ] + } + }, + "op": "Add", + "span": { + "line_start": 10, + "line_stop": 10, + "col_start": 5, + "col_stop": 16, + "path": "" + } + } + }, + "span": { + "line_start": 10, + "line_stop": 10, + "col_start": 5, + "col_stop": 16, + "path": "" + } + } + }, + { + "Console": { + "function": { + "Assert": { + "Binary": { + "left": { + "ArrayAccess": { + "array": { + "Identifier": "{\"name\":\"y\",\"span\":\"{\\\"line_start\\\":11,\\\"line_stop\\\":11,\\\"col_start\\\":20,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}" + }, + "index": { + "Value": { + "Implicit": [ + "0", + { + "line_start": 11, + "line_stop": 11, + "col_start": 22, + "col_stop": 23, + "path": "" + } + ] + } + }, + "span": { + "line_start": 11, + "line_stop": 11, + "col_start": 20, + "col_stop": 24, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "4", + { + "line_start": 11, + "line_stop": 11, + "col_start": 28, + "col_stop": 31, + "path": "" + } + ] + } + }, + "op": "Eq", + "span": { + "line_start": 11, + "line_stop": 11, + "col_start": 20, + "col_stop": 31, + "path": "" + } + } + } + }, + "span": { + "line_start": 11, + "line_stop": 11, + "col_start": 5, + "col_stop": 31, + "path": "" + } + } + }, + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}", + "span": { + "line_start": 13, + "line_stop": 13, + "col_start": 9, + "col_stop": 10, + "path": "" + } + } + ], + "type_": null, + "value": { + "TupleInit": { + "elements": [ + { + "Value": { + "Integer": [ + "U8", + "1", + { + "line_start": 13, + "line_stop": 13, + "col_start": 14, + "col_stop": 17, + "path": "" + } + ] + } + }, + { + "Value": { + "Integer": [ + "U8", + "2", + { + "line_start": 13, + "line_stop": 13, + "col_start": 19, + "col_stop": 22, + "path": "" + } + ] + } + } + ], + "span": { + "line_start": 13, + "line_stop": 13, + "col_start": 13, + "col_stop": 23, + "path": "" + } + } + }, + "span": { + "line_start": 13, + "line_stop": 13, + "col_start": 5, + "col_stop": 23, + "path": "" + } + } + }, + { + "Assign": { + "operation": "Assign", + "assignee": { + "identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}", + "accesses": [ + { + "Tuple": [ + { + "value": "1" + }, + { + "line_start": 14, + "line_stop": 14, + "col_start": 5, + "col_stop": 8, + "path": "" + } + ] + } + ], + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 5, + "col_stop": 8, + "path": "" + } + }, + "value": { + "Binary": { + "left": { + "TupleAccess": { + "tuple": { + "Identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":5,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\"}\"}" + }, + "index": { + "value": "1" + }, + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 5, + "col_stop": 15, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "3", + { + "line_start": 14, + "line_stop": 14, + "col_start": 12, + "col_stop": 15, + "path": "" + } + ] + } + }, + "op": "Add", + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 5, + "col_stop": 15, + "path": "" + } + } + }, + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 5, + "col_stop": 15, + "path": "" + } + } + }, + { + "Console": { + "function": { + "Assert": { + "Binary": { + "left": { + "TupleAccess": { + "tuple": { + "Identifier": "{\"name\":\"z\",\"span\":\"{\\\"line_start\\\":15,\\\"line_stop\\\":15,\\\"col_start\\\":20,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}" + }, + "index": { + "value": "1" + }, + "span": { + "line_start": 15, + "line_stop": 15, + "col_start": 20, + "col_stop": 23, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "5", + { + "line_start": 15, + "line_stop": 15, + "col_start": 27, + "col_stop": 30, + "path": "" + } + ] + } + }, + "op": "Eq", + "span": { + "line_start": 15, + "line_stop": 15, + "col_start": 20, + "col_stop": 30, + "path": "" + } + } + } + }, + "span": { + "line_start": 15, + "line_stop": 15, + "col_start": 5, + "col_stop": 30, + "path": "" + } + } + }, + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", + "span": { + "line_start": 17, + "line_stop": 17, + "col_start": 9, + "col_stop": 12, + "path": "" + } + } + ], + "type_": null, + "value": { + "CircuitInit": { + "name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":15,\\\"col_stop\\\":18,\\\"path\\\":\\\"\\\"}\"}", + "members": [ + { + "identifier": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":17,\\\"line_stop\\\":17,\\\"col_start\\\":21,\\\"col_stop\\\":22,\\\"path\\\":\\\"\\\"}\"}", + "expression": { + "Value": { + "Integer": [ + "U8", + "6", + { + "line_start": 17, + "line_stop": 17, + "col_start": 24, + "col_stop": 27, + "path": "" + } + ] + } + } + } + ], + "span": { + "line_start": 17, + "line_stop": 17, + "col_start": 15, + "col_stop": 29, + "path": "" + } + } + }, + "span": { + "line_start": 17, + "line_stop": 17, + "col_start": 5, + "col_stop": 29, + "path": "" + } + } + }, + { + "Assign": { + "operation": "Assign", + "assignee": { + "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":5,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}", + "accesses": [ + { + "Member": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":9,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}" + } + ], + "span": { + "line_start": 18, + "line_stop": 18, + "col_start": 5, "col_stop": 10, "path": "" } + }, + "value": { + "Binary": { + "left": { + "CircuitMemberAccess": { + "circuit": { + "Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":13,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\"}\"}" + }, + "name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":17,\\\"col_stop\\\":18,\\\"path\\\":\\\"\\\"}\"}", + "span": { + "line_start": 18, + "line_stop": 18, + "col_start": 13, + "col_stop": 18, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "2", + { + "line_start": 18, + "line_stop": 18, + "col_start": 21, + "col_stop": 24, + "path": "" + } + ] + } + }, + "op": "Add", + "span": { + "line_start": 18, + "line_stop": 18, + "col_start": 13, + "col_stop": 24, + "path": "" + } + } + }, + "span": { + "line_start": 18, + "line_stop": 18, + "col_start": 5, + "col_stop": 24, + "path": "" + } + } + }, + { + "Console": { + "function": { + "Assert": { + "Binary": { + "left": { + "CircuitMemberAccess": { + "circuit": { + "Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":19,\\\"line_stop\\\":19,\\\"col_start\\\":20,\\\"col_stop\\\":23,\\\"path\\\":\\\"\\\"}\"}" + }, + "name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":19,\\\"line_stop\\\":19,\\\"col_start\\\":24,\\\"col_stop\\\":25,\\\"path\\\":\\\"\\\"}\"}", + "span": { + "line_start": 19, + "line_stop": 19, + "col_start": 20, + "col_stop": 25, + "path": "" + } + } + }, + "right": { + "Value": { + "Integer": [ + "U8", + "8", + { + "line_start": 19, + "line_stop": 19, + "col_start": 29, + "col_stop": 32, + "path": "" + } + ] + } + }, + "op": "Eq", + "span": { + "line_start": 19, + "line_stop": 19, + "col_start": 20, + "col_stop": 32, + "path": "" + } + } + } + }, + "span": { + "line_start": 19, + "line_stop": 19, + "col_start": 5, + "col_stop": 32, + "path": "" } } - ], - "span": { - "line_start": 1, - "line_stop": 4, - "col_start": 17, - "col_stop": 2, - "path": "" } - }, + ], "span": { - "line_start": 1, - "line_stop": 4, - "col_start": 1, + "line_start": 4, + "line_stop": 20, + "col_start": 17, "col_stop": 2, "path": "" } + }, + "span": { + "line_start": 4, + "line_stop": 20, + "col_start": 1, + "col_stop": 2, + "path": "" } } } - \ No newline at end of file +} From 6774cbb01c833466c0151c83b66d68b7e9f78913 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Mar 2021 11:24:58 -0700 Subject: [PATCH 036/108] fix canonicalization tests --- .../canonicalization/array_expansion.json | 86 ++-- .../big_self_in_circuit_replacement.json | 374 +++++++++--------- .../canonicalization/compound_assignment.json | 220 ++++++----- compiler/tests/canonicalization/mod.rs | 2 + parser/src/parser/file.rs | 6 +- 5 files changed, 365 insertions(+), 323 deletions(-) diff --git a/compiler/tests/canonicalization/array_expansion.json b/compiler/tests/canonicalization/array_expansion.json index 4d321c1e68..70371dfaca 100644 --- a/compiler/tests/canonicalization/array_expansion.json +++ b/compiler/tests/canonicalization/array_expansion.json @@ -4,15 +4,15 @@ "imports": [], "circuits": {}, "functions": { - "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": { + "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}": { "annotations": [], - "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}", + "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}", "input": [ { "Variable": { - "identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\"}\"}", + "identifier": "{\"name\":\"a\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main(a: [group; (2, 1)]) {\\\"}\"}", "const_": false, - "mutable": false, + "mutable": true, "type_": { "Array": [ { @@ -37,7 +37,8 @@ "line_stop": 1, "col_start": 15, "col_stop": 16, - "path": "" + "path": "", + "content": "function main(a: [group; (2, 1)]) {" } } } @@ -52,14 +53,15 @@ "declaration_type": "Let", "variable_names": [ { - "mutable": false, - "identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}", + "mutable": true, + "identifier": "{\"name\":\"b\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let b = [true; (6, 5, 4, 3, 2)];\\\"}\"}", "span": { "line_start": 2, "line_stop": 2, "col_start": 7, "col_stop": 8, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } ], @@ -83,7 +85,8 @@ "line_stop": 2, "col_start": 12, "col_stop": 16, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } ] } @@ -98,7 +101,8 @@ "line_stop": 2, "col_start": 11, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -112,7 +116,8 @@ "line_stop": 2, "col_start": 11, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -126,7 +131,8 @@ "line_stop": 2, "col_start": 11, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -140,7 +146,8 @@ "line_stop": 2, "col_start": 11, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -154,7 +161,8 @@ "line_stop": 2, "col_start": 11, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -163,7 +171,8 @@ "line_stop": 2, "col_start": 3, "col_stop": 34, - "path": "" + "path": "", + "content": " let b = [true; (6, 5, 4, 3, 2)];" } } }, @@ -172,14 +181,15 @@ "declaration_type": "Let", "variable_names": [ { - "mutable": false, - "identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}", + "mutable": true, + "identifier": "{\"name\":\"c\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let c: [u32; (1, 2)] = [0u32; (1, 2)];\\\"}\"}", "span": { "line_start": 3, "line_stop": 3, "col_start": 7, "col_stop": 8, - "path": "" + "path": "", + "content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];" } } ], @@ -218,7 +228,8 @@ "line_stop": 3, "col_start": 27, "col_stop": 31, - "path": "" + "path": "", + "content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];" } ] } @@ -233,7 +244,8 @@ "line_stop": 3, "col_start": 26, "col_stop": 40, - "path": "" + "path": "", + "content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];" } } }, @@ -247,7 +259,8 @@ "line_stop": 3, "col_start": 26, "col_stop": 40, - "path": "" + "path": "", + "content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];" } } }, @@ -256,7 +269,8 @@ "line_stop": 3, "col_start": 3, "col_stop": 40, - "path": "" + "path": "", + "content": " let c: [u32; (1, 2)] = [0u32; (1, 2)];" } } }, @@ -265,14 +279,15 @@ "declaration_type": "Let", "variable_names": [ { - "mutable": false, - "identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}", + "mutable": true, + "identifier": "{\"name\":\"d\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let d = [0i8; (1)];\\\"}\"}", "span": { "line_start": 4, "line_stop": 4, "col_start": 7, "col_stop": 8, - "path": "" + "path": "", + "content": " let d = [0i8; (1)];" } } ], @@ -289,7 +304,8 @@ "line_stop": 4, "col_start": 12, "col_stop": 15, - "path": "" + "path": "", + "content": " let d = [0i8; (1)];" } ] } @@ -304,7 +320,8 @@ "line_stop": 4, "col_start": 11, "col_stop": 21, - "path": "" + "path": "", + "content": " let d = [0i8; (1)];" } } }, @@ -313,26 +330,29 @@ "line_stop": 4, "col_start": 3, "col_stop": 21, - "path": "" + "path": "", + "content": " let d = [0i8; (1)];" } } } ], "span": { "line_start": 1, - "line_stop": 5, + "line_stop": 7, "col_start": 35, "col_stop": 2, - "path": "" + "path": "", + "content": "function main(a: [group; (2, 1)]) {\n...\n}" } }, "span": { "line_start": 1, - "line_stop": 5, + "line_stop": 7, "col_start": 1, "col_stop": 2, - "path": "" + "path": "", + "content": "function main(a: [group; (2, 1)]) {\n...\n}\n\n\n\n" } } } -} +} \ No newline at end of file diff --git a/compiler/tests/canonicalization/big_self_in_circuit_replacement.json b/compiler/tests/canonicalization/big_self_in_circuit_replacement.json index eb63d86b86..a411b9fc05 100644 --- a/compiler/tests/canonicalization/big_self_in_circuit_replacement.json +++ b/compiler/tests/canonicalization/big_self_in_circuit_replacement.json @@ -1,206 +1,218 @@ { - "name": "", - "expected_input": [], - "imports": [], - "circuits": { - "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}": { - "circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", - "members": [ - { - "CircuitVariable": [ - "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}", - { - "IntegerType": "U32" - } - ] - }, - { - "CircuitFunction": { - "annotations": [], - "identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}", - "input": [], - "output": { - "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}" - }, - "block": { - "statements": [ - { - "Definition": { - "declaration_type": "Let", - "variable_names": [ - { - "mutable": false, - "identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", - "span": { - "line_start": 5, - "line_stop": 5, - "col_start": 9, - "col_stop": 12, - "path": "" - } + "name": "", + "expected_input": [], + "imports": [], + "circuits": { + "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}": { + "circuit_name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}", + "members": [ + { + "CircuitVariable": [ + "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: u32\\\"}\"}", + { + "IntegerType": "U32" + } + ] + }, + { + "CircuitFunction": { + "annotations": [], + "identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":4,\\\"line_stop\\\":4,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" function new() -> Self {\\\"}\"}", + "input": [], + "output": { + "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}" + }, + "block": { + "statements": [ + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":5,\\\"line_stop\\\":5,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let new: Self = Self {\\\"}\"}", + "span": { + "line_start": 5, + "line_stop": 5, + "col_start": 9, + "col_stop": 12, + "path": "", + "content": " let new: Self = Self {" } - ], - "type_": { - "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}" - }, - "value": { - "CircuitInit": { - "name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", - "members": [ - { - "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\"}\"}", - "expression": { - "Value": { - "Integer": [ - "U32", - "1", - { - "line_start": 6, - "line_stop": 6, - "col_start": 10, - "col_stop": 14, - "path": "" - } - ] - } + } + ], + "type_": { + "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}" + }, + "value": { + "CircuitInit": { + "name": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":9,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"circuit Foo {\\\"}\"}", + "members": [ + { + "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":6,\\\"line_stop\\\":6,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x: 1u32\\\"}\"}", + "expression": { + "Value": { + "Integer": [ + "U32", + "1", + { + "line_start": 6, + "line_stop": 6, + "col_start": 10, + "col_stop": 14, + "path": "", + "content": " x: 1u32" + } + ] } } - ], - "span": { - "line_start": 5, - "line_stop": 7, - "col_start": 21, - "col_stop": 6, - "path": "" } - } - }, - "span": { - "line_start": 5, - "line_stop": 7, - "col_start": 5, - "col_stop": 6, - "path": "" - } - } - }, - { - "Return": { - "expression": { - "Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}" - }, - "span": { - "line_start": 9, - "line_stop": 9, - "col_start": 5, - "col_stop": 15, - "path": "" - } - } - } - ], - "span": { - "line_start": 4, - "line_stop": 10, - "col_start": 26, - "col_stop": 4, - "path": "" - } - }, - "span": { - "line_start": 4, - "line_stop": 10, - "col_start": 3, - "col_stop": 4, - "path": "" - } - } - } - ] - } - }, - "functions": { - "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": { - "annotations": [], - "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}", - "input": [], - "output": { - "Tuple": [] - }, - "block": { - "statements": [ - { - "Definition": { - "declaration_type": "Let", - "variable_names": [ - { - "mutable": false, - "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\"}\"}", - "span": { - "line_start": 14, - "line_stop": 14, - "col_start": 7, - "col_stop": 10, - "path": "" - } - } - ], - "type_": { - "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\"}\"}" - }, - "value": { - "Call": { - "function": { - "CircuitStaticFunctionAccess": { - "circuit": { - "Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\"}\"}" - }, - "name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\"}\"}", + ], "span": { - "line_start": 14, - "line_stop": 14, - "col_start": 18, - "col_stop": 26, - "path": "" + "line_start": 5, + "line_stop": 7, + "col_start": 21, + "col_stop": 6, + "path": "", + "content": " let new: Self = Self {\n...\n };" } } }, - "arguments": [], "span": { - "line_start": 14, - "line_stop": 14, - "col_start": 18, - "col_stop": 28, - "path": "" + "line_start": 5, + "line_stop": 7, + "col_start": 5, + "col_stop": 6, + "path": "", + "content": " let new: Self = Self {\n...\n };" } } }, - "span": { - "line_start": 14, - "line_stop": 14, - "col_start": 3, - "col_stop": 28, - "path": "" + { + "Return": { + "expression": { + "Identifier": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":9,\\\"line_stop\\\":9,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" return new\\\"}\"}" + }, + "span": { + "line_start": 9, + "line_stop": 9, + "col_start": 5, + "col_stop": 15, + "path": "", + "content": " return new" + } + } } + ], + "span": { + "line_start": 4, + "line_stop": 10, + "col_start": 26, + "col_stop": 4, + "path": "", + "content": " function new() -> Self {\n...\n }" + } + }, + "span": { + "line_start": 4, + "line_stop": 10, + "col_start": 3, + "col_stop": 4, + "path": "", + "content": " function new() -> Self {\n...\n }\n\n\n\n" + } + } + } + ] + } + }, + "functions": { + "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": { + "annotations": [], + "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":13,\\\"line_stop\\\":13,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}", + "input": [], + "output": { + "Tuple": [] + }, + "block": { + "statements": [ + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":7,\\\"col_stop\\\":10,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}", + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 7, + "col_stop": 10, + "path": "", + "content": " let foo: Foo = Foo::new();" + } + } + ], + "type_": { + "Circuit": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":12,\\\"col_stop\\\":15,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}" + }, + "value": { + "Call": { + "function": { + "CircuitStaticFunctionAccess": { + "circuit": { + "Identifier": "{\"name\":\"Foo\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":18,\\\"col_stop\\\":21,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}" + }, + "name": "{\"name\":\"new\",\"span\":\"{\\\"line_start\\\":14,\\\"line_stop\\\":14,\\\"col_start\\\":23,\\\"col_stop\\\":26,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let foo: Foo = Foo::new();\\\"}\"}", + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 18, + "col_stop": 26, + "path": "", + "content": " let foo: Foo = Foo::new();" + } + } + }, + "arguments": [], + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 18, + "col_stop": 28, + "path": "", + "content": " let foo: Foo = Foo::new();" + } + } + }, + "span": { + "line_start": 14, + "line_stop": 14, + "col_start": 3, + "col_stop": 28, + "path": "", + "content": " let foo: Foo = Foo::new();" } } - ], - "span": { - "line_start": 13, - "line_stop": 15, - "col_start": 17, - "col_stop": 2, - "path": "" } - }, + ], "span": { "line_start": 13, "line_stop": 15, - "col_start": 1, + "col_start": 17, "col_stop": 2, - "path": "" + "path": "", + "content": "function main() {\n...\n}" } + }, + "span": { + "line_start": 13, + "line_stop": 15, + "col_start": 1, + "col_stop": 2, + "path": "", + "content": "function main() {\n...\n}" } } } - \ No newline at end of file +} \ No newline at end of file diff --git a/compiler/tests/canonicalization/compound_assignment.json b/compiler/tests/canonicalization/compound_assignment.json index fda6fb09cf..4ce5161420 100644 --- a/compiler/tests/canonicalization/compound_assignment.json +++ b/compiler/tests/canonicalization/compound_assignment.json @@ -1,128 +1,136 @@ { - "name": "", - "expected_input": [], - "imports": [], - "circuits": {}, - "functions": { - "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}": { - "annotations": [], - "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\"}\"}", - "input": [], - "output": { - "Tuple": [] - }, - "block": { - "statements": [ - { - "Definition": { - "declaration_type": "Let", - "variable_names": [ - { - "mutable": true, - "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":11,\\\"col_stop\\\":12,\\\"path\\\":\\\"\\\"}\"}", - "span": { + "name": "", + "expected_input": [], + "imports": [], + "circuits": {}, + "functions": { + "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}": { + "annotations": [], + "identifier": "{\"name\":\"main\",\"span\":\"{\\\"line_start\\\":1,\\\"line_stop\\\":1,\\\"col_start\\\":10,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\"function main() {\\\"}\"}", + "input": [], + "output": { + "Tuple": [] + }, + "block": { + "statements": [ + { + "Definition": { + "declaration_type": "Let", + "variable_names": [ + { + "mutable": true, + "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":2,\\\"line_stop\\\":2,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" let x = 10u32;\\\"}\"}", + "span": { + "line_start": 2, + "line_stop": 2, + "col_start": 7, + "col_stop": 8, + "path": "", + "content": " let x = 10u32;" + } + } + ], + "type_": null, + "value": { + "Value": { + "Integer": [ + "U32", + "10", + { "line_start": 2, "line_stop": 2, - "col_start": 7, - "col_stop": 12, - "path": "" + "col_start": 11, + "col_stop": 16, + "path": "", + "content": " let x = 10u32;" } - } - ], - "type_": null, - "value": { - "Value": { - "Integer": [ - "U32", - "10", - { - "line_start": 2, - "line_stop": 2, - "col_start": 15, - "col_stop": 20, - "path": "" - } - ] - } - }, - "span": { - "line_start": 2, - "line_stop": 2, - "col_start": 3, - "col_stop": 20, - "path": "" + ] } + }, + "span": { + "line_start": 2, + "line_stop": 2, + "col_start": 3, + "col_stop": 16, + "path": "", + "content": " let x = 10u32;" } - }, - { - "Assign": { - "operation": "Assign", - "assignee": { - "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}", - "accesses": [], - "span": { - "line_start": 3, - "line_stop": 3, - "col_start": 3, - "col_stop": 4, - "path": "" - } - }, - "value": { - "Binary": { - "left": { - "Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\"}\"}" - }, - "right": { - "Value": { - "Implicit": [ - "20", - { - "line_start": 3, - "line_stop": 3, - "col_start": 8, - "col_stop": 10, - "path": "" - } - ] - } - }, - "op": "Add", - "span": { - "line_start": 3, - "line_stop": 3, - "col_start": 3, - "col_stop": 10, - "path": "" - } - } - }, + } + }, + { + "Assign": { + "operation": "Assign", + "assignee": { + "identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x += 20;\\\"}\"}", + "accesses": [], "span": { "line_start": 3, "line_stop": 3, "col_start": 3, - "col_stop": 10, - "path": "" + "col_stop": 4, + "path": "", + "content": " x += 20;" } + }, + "value": { + "Binary": { + "left": { + "Identifier": "{\"name\":\"x\",\"span\":\"{\\\"line_start\\\":3,\\\"line_stop\\\":3,\\\"col_start\\\":3,\\\"col_stop\\\":4,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" x += 20;\\\"}\"}" + }, + "right": { + "Value": { + "Implicit": [ + "20", + { + "line_start": 3, + "line_stop": 3, + "col_start": 8, + "col_stop": 10, + "path": "", + "content": " x += 20;" + } + ] + } + }, + "op": "Add", + "span": { + "line_start": 3, + "line_stop": 3, + "col_start": 3, + "col_stop": 10, + "path": "", + "content": " x += 20;" + } + } + }, + "span": { + "line_start": 3, + "line_stop": 3, + "col_start": 3, + "col_stop": 10, + "path": "", + "content": " x += 20;" } } - ], - "span": { - "line_start": 1, - "line_stop": 4, - "col_start": 17, - "col_stop": 2, - "path": "" } - }, + ], "span": { "line_start": 1, "line_stop": 4, - "col_start": 1, + "col_start": 17, "col_stop": 2, - "path": "" + "path": "", + "content": "function main() {\n...\n}" } + }, + "span": { + "line_start": 1, + "line_stop": 4, + "col_start": 1, + "col_stop": 2, + "path": "", + "content": "function main() {\n...\n}\n" } } } - \ No newline at end of file +} \ No newline at end of file diff --git a/compiler/tests/canonicalization/mod.rs b/compiler/tests/canonicalization/mod.rs index fd2db5da3f..0ee24acede 100644 --- a/compiler/tests/canonicalization/mod.rs +++ b/compiler/tests/canonicalization/mod.rs @@ -82,6 +82,8 @@ fn test_compound_assignment() { assert_satisfied(program); let ast = parse_program_ast(program_string); + println!("{}", ast.to_json_string().unwrap()); + let expected_json = include_str!("compound_assignment.json"); let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json."); diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index 11279d06bf..de7f343896 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -328,18 +328,18 @@ impl ParserContext { self.expect_ident()? }; if name.name.as_ref() == "self" { - if let Some(const_) = const_.as_ref() { - return Err(SyntaxError::illegal_self_const(&(&name.span + &const_.span))); - } if let Some(mutable) = &mutable { + // Handle `mut self`. name.span = &mutable.span + &name.span; name.name = "mut self".to_string().into(); return Ok(FunctionInput::MutSelfKeyword(MutSelfKeyword { identifier: name })); } else if let Some(const_) = &const_ { + // Handle `const self`. name.span = &const_.span + &name.span; name.name = "const self".to_string().into(); return Ok(FunctionInput::ConstSelfKeyword(ConstSelfKeyword { identifier: name })); } + // Handle `self`. return Ok(FunctionInput::SelfKeyword(SelfKeyword { identifier: name })); } From 9be13dfd513c95e26b5815c1fe5ebf0f3904103c Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Mar 2021 12:12:38 -0700 Subject: [PATCH 037/108] update comments --- ast/src/errors/error.rs | 2 +- compiler/tests/canonicalization/mod.rs | 2 -- parser/src/tokenizer/lexer.rs | 22 +++++++++++----------- parser/src/tokenizer/mod.rs | 2 +- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/ast/src/errors/error.rs b/ast/src/errors/error.rs index ef6f69337f..6f34ea3463 100644 --- a/ast/src/errors/error.rs +++ b/ast/src/errors/error.rs @@ -21,7 +21,7 @@ use std::{fmt, sync::Arc}; pub const INDENT: &str = " "; /// Formatted compiler error type -/// --> file.leo 2:8 +/// --> file.leo: 2:8 /// | /// 2 | let a = x; /// | ^ diff --git a/compiler/tests/canonicalization/mod.rs b/compiler/tests/canonicalization/mod.rs index 0ee24acede..fd2db5da3f 100644 --- a/compiler/tests/canonicalization/mod.rs +++ b/compiler/tests/canonicalization/mod.rs @@ -82,8 +82,6 @@ fn test_compound_assignment() { assert_satisfied(program); let ast = parse_program_ast(program_string); - println!("{}", ast.to_json_string().unwrap()); - let expected_json = include_str!("compound_assignment.json"); let expected_ast: Ast = Ast::from_json_string(expected_json).expect("Unable to parse json."); diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index 2b1adb4cfe..6e66681f52 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -22,8 +22,8 @@ use tendril::StrTendril; use std::fmt; /// -/// Returns a reference to bytes from the given input if the given string is equal to the bytes, -/// otherwise returns [`None`]. +/// Returns the length of the given `wanted` string if the string can be eaten, otherwise returns [`None`]. +/// A string can be eaten if its bytes are at the front of the given `input` array. /// fn eat(input: &[u8], wanted: &str) -> Option { let wanted = wanted.as_bytes(); @@ -37,8 +37,8 @@ fn eat(input: &[u8], wanted: &str) -> Option { } /// -/// Returns a reference to the bytes of an identifier and the remaining bytes from the given input. -/// Returns [`None`] if the bytes do not represent an identifier. +/// Returns a new `StrTendril` string if an identifier can be eaten, otherwise returns [`None`]. +/// An identifier can be eaten if its bytes are at the front of the given `input_tendril` string. /// fn eat_identifier(input_tendril: &StrTendril) -> Option { if input_tendril.is_empty() { @@ -60,10 +60,10 @@ fn eat_identifier(input_tendril: &StrTendril) -> Option { impl Token { /// - /// Returns a reference to the remaining bytes and the bytes of a number from the given input. - /// Returns [`None`] if the bytes do not represent a number. + /// Returns a tuple: [(integer length, integer token)] if an integer can be eaten, otherwise returns [`None`]. + /// An integer can be eaten if its bytes are at the front of the given `input_tendril` string. /// - fn gobble_int(input_tendril: &StrTendril) -> (usize, Option) { + fn eat_integer(input_tendril: &StrTendril) -> (usize, Option) { if input_tendril.is_empty() { return (0, None); } @@ -93,10 +93,10 @@ impl Token { } /// - /// Returns a reference to the remaining bytes and the bytes of a [`Token`] from the given input. - /// Returns [`None`] if the bytes do not represent a token. + /// Returns a tuple: [(token length, token)] if the next token can be eaten, otherwise returns [`None`]. + /// The next token can be eaten if the bytes at the front of the given `input_tendril` string can be scanned into a token. /// - pub(crate) fn gobble(input_tendril: StrTendril) -> (usize, Option) { + pub(crate) fn eat(input_tendril: StrTendril) -> (usize, Option) { if input_tendril.is_empty() { return (0, None); } @@ -149,7 +149,7 @@ impl Token { return (i + 1, Some(Token::FormattedString(segments))); } x if x.is_ascii_digit() => { - return Self::gobble_int(&input_tendril); + return Self::eat_integer(&input_tendril); } b'!' => { if let Some(len) = eat(input, "!=") { diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index fb64f4222a..de278ef55d 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -39,7 +39,7 @@ pub(crate) fn tokenize(path: &str, input: StrTendril) -> Result index { - match Token::gobble(input.subtendril(index as u32, (input.len() - index) as u32)) { + match Token::eat(input.subtendril(index as u32, (input.len() - index) as u32)) { (token_len, Some(token)) => { let mut span = Span { line_start: line_no, From a763075e990fe88828412eb56955a9f938e12d2f Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 22 Mar 2021 09:38:01 -0700 Subject: [PATCH 038/108] runtime array indexing --- asg/src/error/mod.rs | 8 + asg/src/expression/array_access.rs | 21 ++- asg/src/expression/array_range_access.rs | 103 ++++++++---- compiler/src/errors/expression.rs | 14 +- compiler/src/errors/statement.rs | 12 ++ compiler/src/expression/array/access.rs | 158 +++++++++++++++++- compiler/src/expression/array/index.rs | 6 +- compiler/src/expression/binary/binary.rs | 11 +- compiler/src/expression/expression.rs | 10 +- compiler/src/expression/tuple/access.rs | 2 +- compiler/src/function/mut_target.rs | 20 ++- compiler/src/statement/assign/assignee.rs | 22 ++- compiler/src/statement/iteration/iteration.rs | 11 +- compiler/src/statement/statement.rs | 5 +- compiler/src/value/integer/integer.rs | 10 +- compiler/tests/array/mod.rs | 150 +++++++++++++++++ .../function/array_params_direct_call.leo | 2 +- 17 files changed, 491 insertions(+), 74 deletions(-) diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index 4a8b9143d5..8dd53d098f 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -180,6 +180,14 @@ impl AsgConvertError { Self::new_from_span(format!("tuple index out of bounds: '{}'", index), span) } + pub fn array_index_out_of_bounds(index: usize, span: &Span) -> Self { + Self::new_from_span(format!("array index out of bounds: '{}'", index), span) + } + + pub fn unknown_array_size(span: &Span) -> Self { + Self::new_from_span("array size cannot be inferred, add explicit types".to_string(), span) + } + pub fn unexpected_call_argument_count(expected: usize, got: usize, span: &Span) -> Self { Self::new_from_span( format!("function call expected {} arguments, got {}", expected, got), diff --git a/asg/src/expression/array_access.rs b/asg/src/expression/array_access.rs index 3bbbd7909d..fdf0d185c6 100644 --- a/asg/src/expression/array_access.rs +++ b/asg/src/expression/array_access.rs @@ -89,8 +89,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<' &*value.array, Some(PartialType::Array(expected_type.map(Box::new), None)), )?; - match array.get_type() { - Some(Type::Array(..)) => (), + let array_len = match array.get_type() { + Some(Type::Array(_, len)) => len, type_ => { return Err(AsgConvertError::unexpected_type( "array", @@ -98,7 +98,7 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<' &value.span, )); } - } + }; let index = <&Expression<'a>>::from_ast( scope, @@ -106,10 +106,17 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<' Some(PartialType::Integer(None, Some(IntegerType::U32))), )?; - if !index.is_consty() { - return Err(AsgConvertError::unexpected_nonconst( - &index.span().cloned().unwrap_or_default(), - )); + if let Some(index) = index + .const_value() + .map(|x| x.int().map(|x| x.to_usize()).flatten()) + .flatten() + { + if index > array_len { + return Err(AsgConvertError::array_index_out_of_bounds( + index, + &array.span().cloned().unwrap_or_default(), + )); + } } Ok(ArrayAccessExpression { diff --git a/asg/src/expression/array_range_access.rs b/asg/src/expression/array_range_access.rs index f070116aa0..aec0d79b2e 100644 --- a/asg/src/expression/array_range_access.rs +++ b/asg/src/expression/array_range_access.rs @@ -26,6 +26,9 @@ pub struct ArrayRangeAccessExpression<'a> { pub array: Cell<&'a Expression<'a>>, pub left: Cell>>, pub right: Cell>>, + // this is either const(right) - const(left) OR the length inferred by type checking + // special attention must be made to update this if semantic-altering changes are made to left or right. + pub length: usize, } impl<'a> Node for ArrayRangeAccessExpression<'a> { @@ -55,25 +58,12 @@ impl<'a> ExpressionNode<'a> for ArrayRangeAccessExpression<'a> { } fn get_type(&self) -> Option> { - let (element, array_len) = match self.array.get().get_type() { - Some(Type::Array(element, len)) => (element, len), + let element = match self.array.get().get_type() { + Some(Type::Array(element, _)) => element, _ => return None, }; - let const_left = match self.left.get().map(|x| x.const_value()) { - Some(Some(ConstValue::Int(x))) => x.to_usize()?, - None => 0, - _ => return None, - }; - let const_right = match self.right.get().map(|x| x.const_value()) { - Some(Some(ConstValue::Int(x))) => x.to_usize()?, - None => array_len, - _ => return None, - }; - if const_left > const_right || const_right > array_len { - return None; - } - Some(Type::Array(element, const_right - const_left)) + Some(Type::Array(element, self.length)) } fn is_mut_ref(&self) -> bool { @@ -113,9 +103,9 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx value: &leo_ast::ArrayRangeAccessExpression, expected_type: Option>, ) -> Result, AsgConvertError> { - let expected_array = match expected_type { - Some(PartialType::Array(element, _len)) => Some(PartialType::Array(element, None)), - None => None, + let (expected_array, expected_len) = match expected_type.clone() { + Some(PartialType::Array(element, len)) => (Some(PartialType::Array(element, None)), len), + None => (None, None), Some(x) => { return Err(AsgConvertError::unexpected_type( &x.to_string(), @@ -126,8 +116,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx }; let array = <&Expression<'a>>::from_ast(scope, &*value.array, expected_array)?; let array_type = array.get_type(); - match array_type { - Some(Type::Array(_, _)) => (), + let (parent_element, parent_size) = match array_type { + Some(Type::Array(inner, size)) => (inner, size), type_ => { return Err(AsgConvertError::unexpected_type( "array", @@ -135,7 +125,8 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx &value.span, )); } - } + }; + let left = value .left .as_deref() @@ -151,26 +142,72 @@ impl<'a> FromAst<'a, leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessEx }) .transpose()?; - if let Some(left) = left.as_ref() { - if !left.is_consty() { - return Err(AsgConvertError::unexpected_nonconst( - &left.span().cloned().unwrap_or_default(), - )); + let const_left = match left.map(|x| x.const_value()) { + Some(Some(ConstValue::Int(x))) => x.to_usize(), + None => Some(0), + _ => None, + }; + let const_right = match right.map(|x| x.const_value()) { + Some(Some(ConstValue::Int(value))) => { + let value = value.to_usize(); + if let Some(value) = value { + if value > parent_size { + return Err(AsgConvertError::array_index_out_of_bounds( + value, + &right.unwrap().span().cloned().unwrap_or_default(), + )); + } else if let Some(left) = const_left { + if left > value { + return Err(AsgConvertError::array_index_out_of_bounds( + value, + &right.unwrap().span().cloned().unwrap_or_default(), + )); + } + } + } + value } - } - if let Some(right) = right.as_ref() { - if !right.is_consty() { - return Err(AsgConvertError::unexpected_nonconst( - &right.span().cloned().unwrap_or_default(), - )); + None => Some(parent_size), + _ => None, + }; + + let mut length = if let (Some(left), Some(right)) = (const_left, const_right) { + Some(right - left) + } else { + None + }; + if let Some(expected_len) = expected_len { + if let Some(length) = length { + if length != expected_len { + let concrete_type = Type::Array(parent_element, length); + return Err(AsgConvertError::unexpected_type( + &expected_type.as_ref().unwrap().to_string(), + Some(&concrete_type.to_string()), + &value.span, + )); + } } + if let Some(value) = const_left { + if value + expected_len > parent_size { + return Err(AsgConvertError::array_index_out_of_bounds( + value, + &left.unwrap().span().cloned().unwrap_or_default(), + )); + } + } + length = Some(expected_len); } + if length.is_none() { + return Err(AsgConvertError::unknown_array_size(&value.span)); + } + Ok(ArrayRangeAccessExpression { parent: Cell::new(None), span: Some(value.span.clone()), array: Cell::new(array), left: Cell::new(left), right: Cell::new(right), + length: length.unwrap(), }) } } diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs index 0e4f41a99a..bfa444095f 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -85,12 +85,24 @@ impl ExpressionError { Self::new_from_span(message, span) } - pub fn index_out_of_bounds(index: usize, span: &Span) -> Self { + pub fn tuple_index_out_of_bounds(index: usize, span: &Span) -> Self { let message = format!("cannot access index {} of tuple out of bounds", index); Self::new_from_span(message, span) } + pub fn array_index_out_of_bounds(index: usize, span: &Span) -> Self { + let message = format!("cannot access index {} of array out of bounds", index); + + Self::new_from_span(message, span) + } + + pub fn array_invalid_slice_length(span: &Span) -> Self { + let message = "illegal length of slice".to_string(); + + Self::new_from_span(message, span) + } + pub fn invalid_dimensions(expected: &ArrayDimensions, actual: &ArrayDimensions, span: &Span) -> Self { let message = format!( "expected array dimensions {}, found array dimensions {}", diff --git a/compiler/src/errors/statement.rs b/compiler/src/errors/statement.rs index b3994ee310..6a7d49ca35 100644 --- a/compiler/src/errors/statement.rs +++ b/compiler/src/errors/statement.rs @@ -61,6 +61,12 @@ impl StatementError { Self::new_from_span(message, span) } + pub fn array_assign_index_const(span: &Span) -> Self { + let message = "Cannot assign to non-const array index".to_string(); + + Self::new_from_span(message, span) + } + pub fn array_assign_interior_index(span: &Span) -> Self { let message = "Cannot assign single index to interior of array of values".to_string(); @@ -217,4 +223,10 @@ impl StatementError { Self::new_from_span(message, span) } + + pub fn loop_index_const(span: &Span) -> Self { + let message = "iteration range must be const".to_string(); + + Self::new_from_span(message, span) + } } diff --git a/compiler/src/expression/array/access.rs b/compiler/src/expression/array/access.rs index 97210afd47..629bd30cd2 100644 --- a/compiler/src/expression/array/access.rs +++ b/compiler/src/expression/array/access.rs @@ -16,10 +16,22 @@ //! Enforces array access in a compiled Leo program. -use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_asg::{Expression, Span}; +use crate::{ + arithmetic::*, + errors::ExpressionError, + program::ConstrainedProgram, + relational::*, + value::{ConstrainedValue, Integer}, + GroupType, +}; +use leo_asg::{ConstInt, Expression, Span}; use snarkvm_fields::PrimeField; +use snarkvm_gadgets::utilities::{ + boolean::Boolean, + eq::{EqGadget, EvaluateEqGadget}, + select::CondSelectGadget, +}; use snarkvm_r1cs::ConstraintSystem; impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { @@ -31,13 +43,58 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { index: &'a Expression<'a>, span: &Span, ) -> Result, ExpressionError> { - let array = match self.enforce_expression(cs, array)? { + let mut array = match self.enforce_expression(cs, array)? { ConstrainedValue::Array(array) => array, value => return Err(ExpressionError::undefined_array(value.to_string(), span)), }; let index_resolved = self.enforce_index(cs, index, span)?; - Ok(array[index_resolved].to_owned()) + if let Some(resolved) = index_resolved.to_usize() { + if resolved >= array.len() { + return Err(ExpressionError::array_index_out_of_bounds(resolved, span)); + } + Ok(array[resolved].to_owned()) + } else { + if array.is_empty() { + return Err(ExpressionError::array_index_out_of_bounds(0, span)); + } + { + let bounds_check = evaluate_lt::( + cs, + ConstrainedValue::Integer(index_resolved.clone()), + ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32))), + span, + )?; + let bounds_check = match bounds_check { + ConstrainedValue::Boolean(b) => b, + _ => unimplemented!("illegal non-Integer returned from lt"), + }; + let namespace_string = format!("evaluate array access bounds {}:{}", span.line_start, span.col_start); + let mut unique_namespace = cs.ns(|| namespace_string); + bounds_check + .enforce_equal(&mut unique_namespace, &Boolean::Constant(true)) + .map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?; + } + let mut current_value = array.pop().unwrap(); + for (i, item) in array.into_iter().enumerate() { + let namespace_string = format!("evaluate array access eq {} {}:{}", i, span.line_start, span.col_start); + let eq_namespace = cs.ns(|| namespace_string); + //todo: bounds check static index + let const_index = ConstInt::U32(i as u32).cast_to(&index_resolved.get_type()); + let index_comparison = index_resolved + .evaluate_equal(eq_namespace, &Integer::new(&const_index)) + .map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), span))?; + + //todo: handle out of bounds + let unique_namespace = + cs.ns(|| format!("select array access {} {}:{}", i, span.line_start, span.col_start)); + let value = + ConstrainedValue::conditionally_select(unique_namespace, &index_comparison, &item, ¤t_value) + .map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, span))?; + current_value = value; + } + Ok(current_value) + } } #[allow(clippy::too_many_arguments)] @@ -47,6 +104,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { array: &'a Expression<'a>, left: Option<&'a Expression<'a>>, right: Option<&'a Expression<'a>>, + length: usize, span: &Span, ) -> Result, ExpressionError> { let array = match self.enforce_expression(cs, array)? { @@ -56,12 +114,98 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let from_resolved = match left { Some(from_index) => self.enforce_index(cs, from_index, span)?, - None => 0usize, // Array slice starts at index 0 + None => Integer::new(&ConstInt::U32(0)), // Array slice starts at index 0 }; let to_resolved = match right { Some(to_index) => self.enforce_index(cs, to_index, span)?, - None => array.len(), // Array slice ends at array length + // todo: handle out of bounds for array len + None => Integer::new(&ConstInt::U32(array.len() as u32)), // Array slice ends at array length }; - Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned())) + let const_dimensions = match (from_resolved.to_usize(), to_resolved.to_usize()) { + (Some(from), Some(to)) => Some((from, to)), + (Some(from), None) => Some((from, from + length)), + (None, Some(to)) => Some((to - length, to)), + (None, None) => None, + }; + Ok(if let Some((left, right)) = const_dimensions { + if right - left != length { + return Err(ExpressionError::array_invalid_slice_length(span)); + } + if right > array.len() { + return Err(ExpressionError::array_index_out_of_bounds(right, span)); + } + ConstrainedValue::Array(array[left..right].to_owned()) + } else { + { + let calc_len = enforce_sub::( + cs, + ConstrainedValue::Integer(to_resolved.clone()), + ConstrainedValue::Integer(from_resolved.clone()), + span, + )?; + let calc_len = match calc_len { + ConstrainedValue::Integer(i) => i, + _ => unimplemented!("illegal non-Integer returned from sub"), + }; + let namespace_string = format!( + "evaluate array range access length check {}:{}", + span.line_start, span.col_start + ); + let mut unique_namespace = cs.ns(|| namespace_string); + calc_len + .enforce_equal(&mut unique_namespace, &Integer::new(&ConstInt::U32(length as u32))) + .map_err(|e| ExpressionError::cannot_enforce("array length check".to_string(), e, span))?; + } + { + let bounds_check = evaluate_le::( + cs, + ConstrainedValue::Integer(to_resolved), + ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32))), + span, + )?; + let bounds_check = match bounds_check { + ConstrainedValue::Boolean(b) => b, + _ => unimplemented!("illegal non-Integer returned from le"), + }; + let namespace_string = format!( + "evaluate array range access bounds {}:{}", + span.line_start, span.col_start + ); + let mut unique_namespace = cs.ns(|| namespace_string); + bounds_check + .enforce_equal(&mut unique_namespace, &Boolean::Constant(true)) + .map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?; + } + let mut windows = array.windows(length); + let mut result = ConstrainedValue::Array(vec![]); + + for i in 0..length { + let window = if let Some(window) = windows.next() { + window + } else { + break; + }; + let array_value = ConstrainedValue::Array(window.to_vec()); + let mut unique_namespace = + cs.ns(|| format!("array index eq-check {} {}:{}", i, span.line_start, span.col_start)); + + let equality = evaluate_eq::( + &mut unique_namespace, + ConstrainedValue::Integer(from_resolved.clone()), + ConstrainedValue::Integer(Integer::new(&ConstInt::U32(i as u32))), + span, + )?; + let equality = match equality { + ConstrainedValue::Boolean(b) => b, + _ => unimplemented!("unexpected non-Boolean for evaluate_eq"), + }; + + let unique_namespace = + unique_namespace.ns(|| format!("array index {} {}:{}", i, span.line_start, span.col_start)); + result = ConstrainedValue::conditionally_select(unique_namespace, &equality, &array_value, &result) + .map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, span))?; + } + result + }) } } diff --git a/compiler/src/expression/array/index.rs b/compiler/src/expression/array/index.rs index 1b5dde5a67..7254090320 100644 --- a/compiler/src/expression/array/index.rs +++ b/compiler/src/expression/array/index.rs @@ -16,7 +16,7 @@ //! Enforces an array index expression in a compiled Leo program. -use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; +use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, Integer}; use leo_asg::{Expression, Span}; use snarkvm_fields::PrimeField; @@ -28,9 +28,9 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { cs: &mut CS, index: &'a Expression<'a>, span: &Span, - ) -> Result { + ) -> Result { match self.enforce_expression(cs, index)? { - ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?), + ConstrainedValue::Integer(number) => Ok(number), value => Err(ExpressionError::invalid_index(value.to_string(), span)), } } diff --git a/compiler/src/expression/binary/binary.rs b/compiler/src/expression/binary/binary.rs index d5b250d507..943bbacb64 100644 --- a/compiler/src/expression/binary/binary.rs +++ b/compiler/src/expression/binary/binary.rs @@ -32,8 +32,15 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { left: &'a Expression<'a>, right: &'a Expression<'a>, ) -> Result, ExpressionError> { - let resolved_left = self.enforce_expression(cs, left)?; - let resolved_right = self.enforce_expression(cs, right)?; + let resolved_left = { + let mut left_namespace = cs.ns(|| "left".to_string()); + self.enforce_expression(&mut left_namespace, left)? + }; + + let resolved_right = { + let mut right_namespace = cs.ns(|| "right".to_string()); + self.enforce_expression(&mut right_namespace, right)? + }; Ok((resolved_left, resolved_right)) } diff --git a/compiler/src/expression/expression.rs b/compiler/src/expression/expression.rs index dd966cab90..14e31b4883 100644 --- a/compiler/src/expression/expression.rs +++ b/compiler/src/expression/expression.rs @@ -133,9 +133,13 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => { self.enforce_array_access(cs, array.get(), index.get(), span) } - Expression::ArrayRangeAccess(ArrayRangeAccessExpression { array, left, right, .. }) => { - self.enforce_array_range_access(cs, array.get(), left.get(), right.get(), span) - } + Expression::ArrayRangeAccess(ArrayRangeAccessExpression { + array, + left, + right, + length, + .. + }) => self.enforce_array_range_access(cs, array.get(), left.get(), right.get(), *length, span), // Tuples Expression::TupleInit(TupleInitExpression { elements, .. }) => self.enforce_tuple(cs, &elements[..]), diff --git a/compiler/src/expression/tuple/access.rs b/compiler/src/expression/tuple/access.rs index 11135b810e..842c714ab2 100644 --- a/compiler/src/expression/tuple/access.rs +++ b/compiler/src/expression/tuple/access.rs @@ -40,7 +40,7 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { // Check for out of bounds access. if index > tuple.len() - 1 { // probably safe to be a panic here - return Err(ExpressionError::index_out_of_bounds(index, span)); + return Err(ExpressionError::tuple_index_out_of_bounds(index, span)); } Ok(tuple[index].to_owned()) diff --git a/compiler/src/function/mut_target.rs b/compiler/src/function/mut_target.rs index 913cd974ce..948873ba01 100644 --- a/compiler/src/function/mut_target.rs +++ b/compiler/src/function/mut_target.rs @@ -51,15 +51,31 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let start_index = left .get() .map(|start| self.enforce_index(cs, start, span)) + .transpose()? + .map(|x| { + x.to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(span)) + }) + .transpose()?; + let stop_index = right + .get() + .map(|stop| self.enforce_index(cs, stop, span)) + .transpose()? + .map(|x| { + x.to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(span)) + }) .transpose()?; - let stop_index = right.get().map(|stop| self.enforce_index(cs, stop, span)).transpose()?; output.push(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index)); Ok(inner) } Expression::ArrayAccess(ArrayAccessExpression { array, index, .. }) => { let inner = self.prepare_mut_access(cs, array.get(), span, output)?; - let index = self.enforce_index(cs, index.get(), span)?; + let index = self + .enforce_index(cs, index.get(), span)? + .to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(span))?; output.push(ResolvedAssigneeAccess::ArrayIndex(index)); Ok(inner) diff --git a/compiler/src/statement/assign/assignee.rs b/compiler/src/statement/assign/assignee.rs index 1ae232f289..8baa0ff0a2 100644 --- a/compiler/src/statement/assign/assignee.rs +++ b/compiler/src/statement/assign/assignee.rs @@ -45,19 +45,35 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let start_index = start .get() .map(|start| self.enforce_index(cs, start, &span)) + .transpose()? + .map(|x| { + x.to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(&span)) + }) + .transpose()?; + let stop_index = stop + .get() + .map(|stop| self.enforce_index(cs, stop, &span)) + .transpose()? + .map(|x| { + x.to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(&span)) + }) .transpose()?; - let stop_index = stop.get().map(|stop| self.enforce_index(cs, stop, &span)).transpose()?; Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index)) } AssignAccess::ArrayIndex(index) => { - let index = self.enforce_index(cs, index.get(), &span)?; + let index = self + .enforce_index(cs, index.get(), &span)? + .to_usize() + .ok_or_else(|| StatementError::array_assign_index_const(&span))?; Ok(ResolvedAssigneeAccess::ArrayIndex(index)) } AssignAccess::Tuple(index) => Ok(ResolvedAssigneeAccess::Tuple(*index, span.clone())), AssignAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier.clone())), }) - .collect::, crate::errors::ExpressionError>>()?; + .collect::, StatementError>>()?; let variable = assignee.target_variable.get().borrow(); diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index 0a2b3226af..fc01e33d36 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -17,6 +17,7 @@ //! Enforces an iteration statement in a compiled Leo program. use crate::{ + errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType, @@ -42,8 +43,14 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { let span = statement.span.clone().unwrap_or_default(); - let from = self.enforce_index(cs, statement.start.get(), &span)?; - let to = self.enforce_index(cs, statement.stop.get(), &span)?; + let from = self + .enforce_index(cs, statement.start.get(), &span)? + .to_usize() + .ok_or_else(|| StatementError::loop_index_const(&span))?; + let to = self + .enforce_index(cs, statement.stop.get(), &span)? + .to_usize() + .ok_or_else(|| StatementError::loop_index_const(&span))?; for i in from..to { // Store index in current function scope. diff --git a/compiler/src/statement/statement.rs b/compiler/src/statement/statement.rs index 18b09f810b..53061322b5 100644 --- a/compiler/src/statement/statement.rs +++ b/compiler/src/statement/statement.rs @@ -17,7 +17,7 @@ //! Enforces a statement in a compiled Leo program. use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType}; -use leo_asg::Statement; +use leo_asg::{Node, Statement}; use snarkvm_fields::PrimeField; use snarkvm_gadgets::traits::utilities::boolean::Boolean; @@ -42,6 +42,9 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { statement: &'a Statement<'a>, ) -> StatementResult>> { let mut results = vec![]; + let span = statement.span().cloned().unwrap_or_default(); + let mut cs = cs.ns(|| format!("statement {}:{}", span.line_start, span.col_start)); + let cs = &mut cs; match statement { Statement::Return(statement) => { diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index 40368405ec..3e404c0ecb 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -111,15 +111,9 @@ impl Integer { match_integer!(integer => integer.get_value()) } - pub fn to_usize(&self, span: &Span) -> Result { + pub fn to_usize(&self) -> Option { let unsigned_integer = self; - let value_option: Option = match_unsigned_integer!(unsigned_integer => unsigned_integer.get_value()); - - let value = value_option.ok_or_else(|| IntegerError::invalid_index(span))?; - let value_usize = value - .parse::() - .map_err(|_| IntegerError::invalid_integer(value, span))?; - Ok(value_usize) + match_unsigned_integer!(unsigned_integer => unsigned_integer.get_index()) } pub fn get_type(&self) -> IntegerType { diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index fb01748d2f..ca241eb93e 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -539,3 +539,153 @@ fn test_variable_slice_fail() { expect_asg_error(error); } + +#[test] +fn test_array_index() { + let program_string = r#" + function main(i: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert(2 == b[i]); + console.assert(3 == b[2]); + } + "#; + let input_string = r#" + [main] + i: u32 = 1; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_array_index_bounds_fail() { + let program_string = r#" + function main(i: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert(2 == b[i]); + } + "#; + let input_string = r#" + [main] + i: u32 = 4; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + expect_compiler_error(program); +} + +#[test] +fn test_array_range_index() { + let program_string = r#" + function main(i: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([1u8, 2] == b[0..i]); + console.assert([3u8, 4] == b[i..4]); + } + "#; + let input_string = r#" + [main] + i: u32 = 2; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_array_range_index_dyn() { + let program_string = r#" + function main(i: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([1u8, 2] == b[..i]); + console.assert([3u8, 4] == b[i..]); + } + "#; + let input_string = r#" + [main] + i: u32 = 2; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_array_range_index_full_dyn() { + let program_string = r#" + function main(i: u32, y: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([3u8, 4] == b[i..y]); + } + "#; + let input_string = r#" + [main] + i: u32 = 2; + y: u32 = 4; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + assert_satisfied(program); +} + +#[test] +fn test_array_range_index_fail_bounds() { + let program_string = r#" + function main(i: u32, y: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([1, 2] == b[3..5]); + } + "#; + let input_string = r#" + [main] + i: u32 = 2; + "#; + let err = parse_program_with_input(program_string, input_string).is_err(); + + assert!(err); +} + +#[test] +fn test_array_range_index_full_dyn_resized_fail() { + let program_string = r#" + function main(i: u32, y: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([3u8, 4] == b[i..y]); + } + "#; + let input_string = r#" + [main] + i: u32 = 1; + y: u32 = 4; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + expect_compiler_error(program); +} + +#[test] +fn test_array_range_index_full_dyn_bounds_fail() { + let program_string = r#" + function main(i: u32, y: u32) { + let b = [1u8, 2, 3, 4]; + + console.assert([3u8, 4] == b[i..y]); + } + "#; + let input_string = r#" + [main] + i: u32 = 3; + y: u32 = 5; + "#; + let program = parse_program_with_input(program_string, input_string).unwrap(); + + expect_compiler_error(program); +} diff --git a/compiler/tests/function/array_params_direct_call.leo b/compiler/tests/function/array_params_direct_call.leo index 8ded724bc4..86762aabc7 100644 --- a/compiler/tests/function/array_params_direct_call.leo +++ b/compiler/tests/function/array_params_direct_call.leo @@ -5,5 +5,5 @@ function main() { do_nothing(arr); do_nothing([...arr]); - do_nothing(arr[1u32..]); + do_nothing(arr[0u32..]); } \ No newline at end of file From dca215cfb16fe6743b5d5ded753ea77937c70173 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Mar 2021 14:26:11 -0700 Subject: [PATCH 039/108] pass input length through --- asg/src/reducer/reconstructing_reducer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/asg/src/reducer/reconstructing_reducer.rs b/asg/src/reducer/reconstructing_reducer.rs index c1b19e4bba..3e38d4cc7a 100644 --- a/asg/src/reducer/reconstructing_reducer.rs +++ b/asg/src/reducer/reconstructing_reducer.rs @@ -74,6 +74,7 @@ pub trait ReconstructingReducerExpression<'a> { left: Cell::new(left), right: Cell::new(right), span: input.span, + length: input.length, }) } From 426cfbc88c07e1813fd33113977e3a94b7c769d0 Mon Sep 17 00:00:00 2001 From: Protryon Date: Mon, 29 Mar 2021 15:57:17 -0700 Subject: [PATCH 040/108] address todos --- compiler/src/errors/expression.rs | 12 ++++++++++++ compiler/src/expression/array/access.rs | 26 +++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs index bfa444095f..e472688f5b 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -67,6 +67,18 @@ impl ExpressionError { Self::new_from_span(message, span) } + pub fn array_length_out_of_bounds(span: &Span) -> Self { + let message = "array length cannot be >= 2^32".to_string(); + + Self::new_from_span(message, span) + } + + pub fn array_index_out_of_legal_bounds(span: &Span) -> Self { + let message = "array index cannot be >= 2^32".to_string(); + + Self::new_from_span(message, span) + } + pub fn conditional_boolean(actual: String, span: &Span) -> Self { let message = format!("if, else conditional must resolve to a boolean, found `{}`", actual); diff --git a/compiler/src/expression/array/access.rs b/compiler/src/expression/array/access.rs index 629bd30cd2..58544548b7 100644 --- a/compiler/src/expression/array/access.rs +++ b/compiler/src/expression/array/access.rs @@ -16,6 +16,8 @@ //! Enforces array access in a compiled Leo program. +use std::convert::TryInto; + use crate::{ arithmetic::*, errors::ExpressionError, @@ -59,10 +61,14 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { return Err(ExpressionError::array_index_out_of_bounds(0, span)); } { + let array_len: u32 = array + .len() + .try_into() + .map_err(|_| ExpressionError::array_length_out_of_bounds(span))?; let bounds_check = evaluate_lt::( cs, ConstrainedValue::Integer(index_resolved.clone()), - ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32))), + ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array_len))), span, )?; let bounds_check = match bounds_check { @@ -75,17 +81,20 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { .enforce_equal(&mut unique_namespace, &Boolean::Constant(true)) .map_err(|e| ExpressionError::cannot_enforce("array bounds check".to_string(), e, span))?; } + let mut current_value = array.pop().unwrap(); for (i, item) in array.into_iter().enumerate() { let namespace_string = format!("evaluate array access eq {} {}:{}", i, span.line_start, span.col_start); let eq_namespace = cs.ns(|| namespace_string); - //todo: bounds check static index - let const_index = ConstInt::U32(i as u32).cast_to(&index_resolved.get_type()); + + let index_bounded = i + .try_into() + .map_err(|_| ExpressionError::array_index_out_of_legal_bounds(span))?; + let const_index = ConstInt::U32(index_bounded).cast_to(&index_resolved.get_type()); let index_comparison = index_resolved .evaluate_equal(eq_namespace, &Integer::new(&const_index)) .map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), span))?; - //todo: handle out of bounds let unique_namespace = cs.ns(|| format!("select array access {} {}:{}", i, span.line_start, span.col_start)); let value = @@ -118,8 +127,13 @@ impl<'a, F: PrimeField, G: GroupType> ConstrainedProgram<'a, F, G> { }; let to_resolved = match right { Some(to_index) => self.enforce_index(cs, to_index, span)?, - // todo: handle out of bounds for array len - None => Integer::new(&ConstInt::U32(array.len() as u32)), // Array slice ends at array length + None => { + let index_bounded: u32 = array + .len() + .try_into() + .map_err(|_| ExpressionError::array_length_out_of_bounds(span))?; + Integer::new(&ConstInt::U32(index_bounded)) + } // Array slice ends at array length }; let const_dimensions = match (from_resolved.to_usize(), to_resolved.to_usize()) { (Some(from), Some(to)) => Some((from, to)), From c352f41d419d483602ff131541410a87c16b432c Mon Sep 17 00:00:00 2001 From: Collin Chin Date: Mon, 29 Mar 2021 22:12:06 -0700 Subject: [PATCH 041/108] add silly-sudoku example --- examples/silly-sudoku/.gitignore | 2 + examples/silly-sudoku/Leo.toml | 8 +++ examples/silly-sudoku/README.md | 23 ++++++ examples/silly-sudoku/inputs/silly-sudoku.in | 12 ++++ .../silly-sudoku/inputs/silly-sudoku.state | 26 +++++++ examples/silly-sudoku/src/lib.leo | 70 ++++++++++++++++++ examples/silly-sudoku/src/main.leo | 71 +++++++++++++++++++ 7 files changed, 212 insertions(+) create mode 100644 examples/silly-sudoku/.gitignore create mode 100644 examples/silly-sudoku/Leo.toml create mode 100644 examples/silly-sudoku/README.md create mode 100644 examples/silly-sudoku/inputs/silly-sudoku.in create mode 100644 examples/silly-sudoku/inputs/silly-sudoku.state create mode 100644 examples/silly-sudoku/src/lib.leo create mode 100644 examples/silly-sudoku/src/main.leo diff --git a/examples/silly-sudoku/.gitignore b/examples/silly-sudoku/.gitignore new file mode 100644 index 0000000000..ef3a390676 --- /dev/null +++ b/examples/silly-sudoku/.gitignore @@ -0,0 +1,2 @@ +outputs/ +/.leo diff --git a/examples/silly-sudoku/Leo.toml b/examples/silly-sudoku/Leo.toml new file mode 100644 index 0000000000..aecf26ff25 --- /dev/null +++ b/examples/silly-sudoku/Leo.toml @@ -0,0 +1,8 @@ +[project] +name = "silly-sudoku" +version = "0.1.3" +description = "A simple Sudoku puzzle grid" +license = "MIT" + +[remote] +author = "howard" diff --git a/examples/silly-sudoku/README.md b/examples/silly-sudoku/README.md new file mode 100644 index 0000000000..59eada079d --- /dev/null +++ b/examples/silly-sudoku/README.md @@ -0,0 +1,23 @@ +# silly-sudoku + +A simple Sudoku puzzle grid in Leo. + +## Walkthrough + +Start by defining a puzzle grid: +``` +[[0, 4, 6], + [3, 0, 9], + [7, 5, 0]] +``` +We treat all 0's as empty cells in the grid. + +Next, generate an answer and construct it as a puzzle grid solution: +``` +[[8, 4, 6], + [3, 1, 9], + [7, 5, 2]] +``` + +The SillySudoku circuit will proceed to verify that the solution grid matches the starting puzzle grid, +and check that each number between 1 - 9 is used exactly once. diff --git a/examples/silly-sudoku/inputs/silly-sudoku.in b/examples/silly-sudoku/inputs/silly-sudoku.in new file mode 100644 index 0000000000..609960e49a --- /dev/null +++ b/examples/silly-sudoku/inputs/silly-sudoku.in @@ -0,0 +1,12 @@ +// The program input for tmp-test/src/main.leo +[main] +puzzle: [u8; (3, 3)] = [[0, 2, 0], + [0, 0, 6], + [0, 8, 9]]; + +answer: [u8; (3, 3)] = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]; + +[registers] +r: bool = false; diff --git a/examples/silly-sudoku/inputs/silly-sudoku.state b/examples/silly-sudoku/inputs/silly-sudoku.state new file mode 100644 index 0000000000..440054cd02 --- /dev/null +++ b/examples/silly-sudoku/inputs/silly-sudoku.state @@ -0,0 +1,26 @@ +// The program state for tmp-test/src/main.leo +[[public]] + +[state] +leaf_index: u32 = 0; +root: [u8; 32] = [0; 32]; + +[[private]] + +[record] +serial_number: [u8; 64] = [0; 64]; +commitment: [u8; 32] = [0; 32]; +owner: address = aleo1daxej63vwrmn2zhl4dymygagh89k5d2vaw6rjauueme7le6k2q8sjn0ng9; +is_dummy: bool = false; +value: u64 = 0; +payload: [u8; 32] = [0; 32]; +birth_program_id: [u8; 48] = [0; 48]; +death_program_id: [u8; 48] = [0; 48]; +serial_number_nonce: [u8; 32] = [0; 32]; +commitment_randomness: [u8; 32] = [0; 32]; + +[state_leaf] +path: [u8; 128] = [0; 128]; +memo: [u8; 32] = [0; 32]; +network_id: u8 = 0; +leaf_randomness: [u8; 32] = [0; 32]; diff --git a/examples/silly-sudoku/src/lib.leo b/examples/silly-sudoku/src/lib.leo new file mode 100644 index 0000000000..0e5c93568e --- /dev/null +++ b/examples/silly-sudoku/src/lib.leo @@ -0,0 +1,70 @@ +/** + * The SillySudoku circuit + * + * This circuit generates a silly Sudoku puzzle, + * by constructing a 3x3 puzzle grid with some preset numbers 1-9, + * and requiring an answer where each number is used exactly once. + * + * ----------- + * | 5 | 8 | 3 | + * |-----------| + * | 2 | 7 | 4 | + * |-----------| + * | 1 | 9 | 6 | + * ----------- + */ +circuit SillySudoku { + // The starting grid values for the Sudoku puzzle. + // Unset cells on the puzzle grid are set to 0. + puzzle_grid: [u8; (3, 3)], + + /** + * Returns true if a given Sudoku answer is correct. + * + * Verifies a given answer by iterating through the Sudoku puzzle, + * and checking that each number is set exactly once. + */ + function solve(self, answer: [u8; (3, 3)]) -> bool { + // The result boolean is set to true, if the answer is correct. + let result = true; + // An array that tracks the numbers used on the Sudoku grid. + let seen = [false; 9]; + + // Iterate through the Sudoku grid and check each cell. + for i in 0..3 { + for j in 0..3 { + + // Fetch the current cell value for the Sudoku grid. + let grid_value = self.puzzle_grid[i][j]; + + // Fetch the current cell value for the given answer. + let answer_value = answer[i][j]; + + // Set the index by subtracting 1 from the answer value. + let index = answer_value - 1; + + // Check if this number has already been used on the grid. + let already_seen: bool = seen[index]; + + // If this number is already used, the answer is incorrect. + // Sets the result to false. + if already_seen { + result = false; + } + + // If the cell is not empty, and the grid value doesn't match + // the answer value, the answer is incorrect. + // Sets the result to false. + if (grid_value != 0 && grid_value != answer_value) { + result = false; + } + + // Sets the answer value as seen. + seen[index] = true; + } + } + + // Returns true if all numbers 1-9 have been seen exactly once. + return result + } +} diff --git a/examples/silly-sudoku/src/main.leo b/examples/silly-sudoku/src/main.leo new file mode 100644 index 0000000000..087acda62d --- /dev/null +++ b/examples/silly-sudoku/src/main.leo @@ -0,0 +1,71 @@ +import lib.SillySudoku; + +// The `silly-sudoku` main function +function main(puzzle: [u8; (3, 3)], answer: [u8; (3, 3)]) -> bool { + console.log("Starting Sudoku solver..."); + console.log("{}", puzzle); + + // Instantiate the Sudoku puzzle. + let sudoku = SillySudoku { puzzle_grid: puzzle }; + + console.log("Checking Sudoku answer..."); + console.log("{}", answer); + + // Evaluate the Sudoku puzzle with the given answer. + let result = sudoku.solve(answer); + + console.log("The answer is {}.", result); + + return result +} + +// Tests that the `silly-sudoku` circuit outputs true on a correct answer. +@test +function test_solve_pass() { + let puzzle: [u8; (3, 3)] = [[0, 2, 0], + [0, 0, 6], + [0, 8, 9]]; + + let answer: [u8; (3, 3)] = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]; + + // Runs the Sudoku checker. + let result = main(puzzle, answer); + + // Expects the result to be true. + console.assert(true == result); +} + +// Tests that the `silly-sudoku` circuit outputs false on an incorrect answer. +@test +function test_solve_fail() { + let puzzle: [u8; (3, 3)] = [[0, 2, 0], + [0, 0, 6], + [0, 8, 0]]; + + let answer: [u8; (3, 3)] = [[1, 2, 3], + [4, 5, 6], + [7, 8, 8]]; // We have an extra `8` in this column! + + // Runs the Sudoku checker. + let result = main(puzzle, answer); + + // Expects the result to be false. + console.assert(false == result); +} + +// Test that the `silly-sudoku` circuit outputs the expected value on a custom test input. +@test(test_input) +function test_solve_with_input( + puzzle: [u8; (3, 3)], + answer: [u8; (3, 3)], + expected: bool +) { + // Runs the Sudoku checker. + let result = main(puzzle, answer); + + console.log("expected {}, got {}", expected, result); + + console.assert(expected == result); +} From b80cc62368b85083649222ca4bdac89a2ba7eac4 Mon Sep 17 00:00:00 2001 From: damirka Date: Tue, 30 Mar 2021 11:43:44 +0300 Subject: [PATCH 042/108] adds --path argument to Leo command - also features small change in architecture - context is now created in main --- leo/commands/build.rs | 2 +- leo/commands/clean.rs | 2 +- leo/commands/deploy.rs | 2 +- leo/commands/init.rs | 2 +- leo/commands/lint.rs | 2 +- leo/commands/mod.rs | 19 ++++-------- leo/commands/new.rs | 2 +- leo/commands/package/add.rs | 2 +- leo/commands/package/clone.rs | 2 +- leo/commands/package/login.rs | 2 +- leo/commands/package/logout.rs | 2 +- leo/commands/package/publish.rs | 4 +-- leo/commands/package/remove.rs | 2 +- leo/commands/prove.rs | 4 +-- leo/commands/run.rs | 4 +-- leo/commands/setup.rs | 4 +-- leo/commands/test.rs | 2 +- leo/commands/update.rs | 2 +- leo/commands/watch.rs | 6 ++-- leo/main.rs | 52 ++++++++++++++++++++------------- 20 files changed, 61 insertions(+), 58 deletions(-) diff --git a/leo/commands/build.rs b/leo/commands/build.rs index badfec2e15..392859e238 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -45,7 +45,7 @@ impl Command for Build { tracing::span!(tracing::Level::INFO, "Build") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/clean.rs b/leo/commands/clean.rs index 0b39661f07..83c2503555 100644 --- a/leo/commands/clean.rs +++ b/leo/commands/clean.rs @@ -35,7 +35,7 @@ impl Command for Clean { tracing::span!(tracing::Level::INFO, "Cleaning") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/deploy.rs b/leo/commands/deploy.rs index 06eff0c2e6..fa421e14ab 100644 --- a/leo/commands/deploy.rs +++ b/leo/commands/deploy.rs @@ -33,7 +33,7 @@ impl Command for Deploy { tracing::span!(tracing::Level::INFO, "Deploy") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/init.rs b/leo/commands/init.rs index 7c6b3e7745..a4d07a9137 100644 --- a/leo/commands/init.rs +++ b/leo/commands/init.rs @@ -35,7 +35,7 @@ impl Command for Init { tracing::span!(tracing::Level::INFO, "Initializing") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/lint.rs b/leo/commands/lint.rs index 3e60d7ec6e..c3f948acc9 100644 --- a/leo/commands/lint.rs +++ b/leo/commands/lint.rs @@ -33,7 +33,7 @@ impl Command for Lint { tracing::span!(tracing::Level::INFO, "Linting") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/mod.rs b/leo/commands/mod.rs index 47d5994575..7f5f2349fb 100644 --- a/leo/commands/mod.rs +++ b/leo/commands/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::context::{get_context, Context}; +use crate::context::Context; use anyhow::Result; use std::time::Instant; @@ -72,11 +72,6 @@ pub trait Command { /// this field may be left empty. type Output; - /// Returns the project context, which is defined as the current directory. - fn context(&self) -> Result { - get_context() - } - /// Adds a span to the logger via `tracing::span`. /// Because of the specifics of the macro implementation, it is not possible /// to set the span name with a non-literal i.e. a dynamic variable even if this @@ -86,7 +81,7 @@ pub trait Command { } /// Runs the prelude and returns the Input of the current command. - fn prelude(&self) -> Result + fn prelude(&self, context: Context) -> Result where Self: std::marker::Sized; @@ -98,11 +93,11 @@ pub trait Command { /// A wrapper around the `apply` method. /// This function sets up tracing, timing, and the context. - fn execute(self) -> Result + fn execute(self, context: Context) -> Result where Self: std::marker::Sized, { - let input = self.prelude()?; + let input = self.prelude(context.clone())?; // Create the span for this command. let span = self.log_span(); @@ -110,8 +105,6 @@ pub trait Command { // Calculate the execution time for this command. let timer = Instant::now(); - - let context = self.context()?; let out = self.apply(context, input); drop(span); @@ -127,10 +120,10 @@ pub trait Command { /// Executes command but empty the result. Comes in handy where there's a /// need to make match arms compatible while keeping implementation-specific /// output possible. Errors however are all of the type Error - fn try_execute(self) -> Result<()> + fn try_execute(self, context: Context) -> Result<()> where Self: std::marker::Sized, { - self.execute().map(|_| Ok(()))? + self.execute(context).map(|_| Ok(()))? } } diff --git a/leo/commands/new.rs b/leo/commands/new.rs index a4da67c309..c77448cfc4 100644 --- a/leo/commands/new.rs +++ b/leo/commands/new.rs @@ -38,7 +38,7 @@ impl Command for New { tracing::span!(tracing::Level::INFO, "New") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/package/add.rs b/leo/commands/package/add.rs index ef1491f2f9..5b540617ba 100644 --- a/leo/commands/package/add.rs +++ b/leo/commands/package/add.rs @@ -86,7 +86,7 @@ impl Command for Add { tracing::span!(tracing::Level::INFO, "Adding") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/package/clone.rs b/leo/commands/package/clone.rs index 5b5e6acdcf..92cad951cd 100644 --- a/leo/commands/package/clone.rs +++ b/leo/commands/package/clone.rs @@ -103,7 +103,7 @@ impl Command for Clone { tracing::span!(tracing::Level::INFO, "Cloning") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/package/login.rs b/leo/commands/package/login.rs index 25425fccb0..495f52b6e5 100644 --- a/leo/commands/package/login.rs +++ b/leo/commands/package/login.rs @@ -54,7 +54,7 @@ impl Command for Login { tracing::span!(tracing::Level::INFO, "Login") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/package/logout.rs b/leo/commands/package/logout.rs index 6bd76a2575..c6018854ef 100644 --- a/leo/commands/package/logout.rs +++ b/leo/commands/package/logout.rs @@ -34,7 +34,7 @@ impl Command for Logout { tracing::span!(tracing::Level::INFO, "Logout") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/package/publish.rs b/leo/commands/package/publish.rs index 7b86763c67..088949600b 100644 --- a/leo/commands/package/publish.rs +++ b/leo/commands/package/publish.rs @@ -46,8 +46,8 @@ impl Command for Publish { type Output = Option; /// Build program before publishing - fn prelude(&self) -> Result { - (Build {}).execute() + fn prelude(&self, context: Context) -> Result { + (Build {}).execute(context) } fn apply(self, context: Context, _input: Self::Input) -> Result { diff --git a/leo/commands/package/remove.rs b/leo/commands/package/remove.rs index f0df722146..1f5426062c 100644 --- a/leo/commands/package/remove.rs +++ b/leo/commands/package/remove.rs @@ -37,7 +37,7 @@ impl Command for Remove { tracing::span!(tracing::Level::INFO, "Removing") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/prove.rs b/leo/commands/prove.rs index da99c84aed..79c12fefcc 100644 --- a/leo/commands/prove.rs +++ b/leo/commands/prove.rs @@ -45,9 +45,9 @@ impl Command for Prove { tracing::span!(tracing::Level::INFO, "Proving") } - fn prelude(&self) -> Result { + fn prelude(&self, context: Context) -> Result { let skip_key_check = self.skip_key_check; - (Setup { skip_key_check }).execute() + (Setup { skip_key_check }).execute(context) } fn apply(self, context: Context, input: Self::Input) -> Result { diff --git a/leo/commands/run.rs b/leo/commands/run.rs index eeec6fc02d..cfdac6f6ac 100644 --- a/leo/commands/run.rs +++ b/leo/commands/run.rs @@ -40,9 +40,9 @@ impl Command for Run { tracing::span!(tracing::Level::INFO, "Verifying") } - fn prelude(&self) -> Result { + fn prelude(&self, context: Context) -> Result { let skip_key_check = self.skip_key_check; - (Prove { skip_key_check }).execute() + (Prove { skip_key_check }).execute(context) } fn apply(self, _context: Context, input: Self::Input) -> Result { diff --git a/leo/commands/setup.rs b/leo/commands/setup.rs index df1d3a0537..2553129f7d 100644 --- a/leo/commands/setup.rs +++ b/leo/commands/setup.rs @@ -49,8 +49,8 @@ impl Command for Setup { tracing::span!(tracing::Level::INFO, "Setup") } - fn prelude(&self) -> Result { - (Build {}).execute() + fn prelude(&self, context: Context) -> Result { + (Build {}).execute(context) } fn apply(self, context: Context, input: Self::Input) -> Result { diff --git a/leo/commands/test.rs b/leo/commands/test.rs index f5de8672f2..4810b8189a 100644 --- a/leo/commands/test.rs +++ b/leo/commands/test.rs @@ -47,7 +47,7 @@ impl Command for Test { tracing::span!(tracing::Level::INFO, "Test") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/update.rs b/leo/commands/update.rs index f3027e5907..605633b730 100644 --- a/leo/commands/update.rs +++ b/leo/commands/update.rs @@ -54,7 +54,7 @@ impl Command for Update { tracing::span!(tracing::Level::INFO, "Updating") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } diff --git a/leo/commands/watch.rs b/leo/commands/watch.rs index 7a98b9604f..77e9e5f304 100644 --- a/leo/commands/watch.rs +++ b/leo/commands/watch.rs @@ -43,11 +43,11 @@ impl Command for Watch { tracing::span!(tracing::Level::INFO, "Watching") } - fn prelude(&self) -> Result { + fn prelude(&self, _: Context) -> Result { Ok(()) } - fn apply(self, _context: Context, _: Self::Input) -> Result { + fn apply(self, context: Context, _: Self::Input) -> Result { let (tx, rx) = channel(); let mut watcher = watcher(tx, Duration::from_secs(self.interval)).unwrap(); @@ -64,7 +64,7 @@ impl Command for Watch { match rx.recv() { // See changes on the write event Ok(DebouncedEvent::Write(_write)) => { - match (Build {}).execute() { + match (Build {}).execute(context.clone()) { Ok(_output) => { tracing::info!("Built successfully"); } diff --git a/leo/main.rs b/leo/main.rs index a0d256230c..226dbd89fb 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -39,7 +39,7 @@ use commands::{ }; use anyhow::Error; -use std::process::exit; +use std::{path::PathBuf, process::exit}; use structopt::{clap::AppSettings, StructOpt}; /// CLI Arguments entry point - includes global parameters and subcommands @@ -54,6 +54,9 @@ struct Opt { #[structopt(subcommand)] command: CommandOpts, + + #[structopt(short, long, help = "Optional path to Leo program root folder", parse(from_os_str))] + path: Option, } ///Leo compiler and package manager @@ -170,38 +173,45 @@ enum CommandOpts { } fn main() { - // read command line arguments + // Read command line arguments. let opt = Opt::from_args(); if !opt.quiet { - // init logger with optional debug flag + // Init logger with optional debug flag. logger::init_logger("leo", match opt.debug { false => 1, true => 2, }); } + // Get custom root folder and create context for it. + // If not specified, default context will be created in cwd. + let context = handle_error(match opt.path { + Some(path) => context::create_context(path), + None => context::get_context(), + }); + handle_error(match opt.command { - CommandOpts::Init { command } => command.try_execute(), - CommandOpts::New { command } => command.try_execute(), - CommandOpts::Build { command } => command.try_execute(), - CommandOpts::Setup { command } => command.try_execute(), - CommandOpts::Prove { command } => command.try_execute(), - CommandOpts::Test { command } => command.try_execute(), - CommandOpts::Run { command } => command.try_execute(), - CommandOpts::Clean { command } => command.try_execute(), - CommandOpts::Watch { command } => command.try_execute(), - CommandOpts::Update { command } => command.try_execute(), + CommandOpts::Init { command } => command.try_execute(context), + CommandOpts::New { command } => command.try_execute(context), + CommandOpts::Build { command } => command.try_execute(context), + CommandOpts::Setup { command } => command.try_execute(context), + CommandOpts::Prove { command } => command.try_execute(context), + CommandOpts::Test { command } => command.try_execute(context), + CommandOpts::Run { command } => command.try_execute(context), + CommandOpts::Clean { command } => command.try_execute(context), + CommandOpts::Watch { command } => command.try_execute(context), + CommandOpts::Update { command } => command.try_execute(context), - CommandOpts::Add { command } => command.try_execute(), - CommandOpts::Clone { command } => command.try_execute(), - CommandOpts::Login { command } => command.try_execute(), - CommandOpts::Logout { command } => command.try_execute(), - CommandOpts::Publish { command } => command.try_execute(), - CommandOpts::Remove { command } => command.try_execute(), + CommandOpts::Add { command } => command.try_execute(context), + CommandOpts::Clone { command } => command.try_execute(context), + CommandOpts::Login { command } => command.try_execute(context), + CommandOpts::Logout { command } => command.try_execute(context), + CommandOpts::Publish { command } => command.try_execute(context), + CommandOpts::Remove { command } => command.try_execute(context), - CommandOpts::Lint { command } => command.try_execute(), - CommandOpts::Deploy { command } => command.try_execute(), + CommandOpts::Lint { command } => command.try_execute(context), + CommandOpts::Deploy { command } => command.try_execute(context), }); } From 3eadb89c2951ad38221901be294fb4174c52efdc Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 30 Mar 2021 12:50:57 -0400 Subject: [PATCH 043/108] fix inferred, not sure why single line comments are failing --- HEAD | 0 parser/src/parser/context.rs | 4 ---- parser/src/tokenizer/lexer.rs | 2 +- parser/src/tokenizer/mod.rs | 3 +-- 4 files changed, 2 insertions(+), 7 deletions(-) create mode 100644 HEAD diff --git a/HEAD b/HEAD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index f8132c0782..91014c4f87 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -303,10 +303,6 @@ impl ParserContext { span, } = token { - // if name.starts_with('_') { - // return Err(SyntaxError::invalid_ident_name(&name, &name[1..name.len()], &span)); - // } - Ok(Identifier { name, span }) } else { unimplemented!() diff --git a/parser/src/tokenizer/lexer.rs b/parser/src/tokenizer/lexer.rs index ee3a468cba..602e39a5c8 100644 --- a/parser/src/tokenizer/lexer.rs +++ b/parser/src/tokenizer/lexer.rs @@ -46,7 +46,6 @@ fn eat_identifier(input_tendril: &StrTendril) -> Option { } let input = input_tendril[..].as_bytes(); if !input[0].is_ascii_alphabetic() { - // Allow _ at start. return None; } @@ -176,6 +175,7 @@ impl Token { } b'(' => return (1, Some(Token::LeftParen)), b')' => return (1, Some(Token::RightParen)), + b'_' => return (1, Some(Token::Underscore)), b'*' => { if let Some(len) = eat(input, "**") { if let Some(inner_len) = eat(&input[len..], "=") { diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 9125dd72e5..9637eabbdb 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -229,8 +229,7 @@ mod tests { assert_eq!( output, r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test - /* test */ // - "# + /* test */ // "# ); } From 8d2ec0dbda3bb0ebce541f4a60b33c72fa1b05ca Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 30 Mar 2021 12:51:23 -0400 Subject: [PATCH 044/108] remove head file --- HEAD | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 HEAD diff --git a/HEAD b/HEAD deleted file mode 100644 index e69de29bb2..0000000000 From addb54a3f40915827fab2e820ea72ea7a32be924 Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 30 Mar 2021 15:13:02 -0400 Subject: [PATCH 045/108] no clue what change is causing this --- parser/src/parser/expression.rs | 3 +-- parser/src/tokenizer/mod.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index 627d8c195b..3b5d88fc0b 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -311,8 +311,7 @@ impl ParserContext { /// Otherwise, tries to parse the next token using [`parse_cast_expression`]. /// pub fn parse_exponential_expression(&mut self) -> SyntaxResult { - let mut exprs = vec![]; - exprs.push(self.parse_cast_expression()?); + let mut exprs = vec![self.parse_cast_expression()?]; while self.eat(Token::Exp).is_some() { exprs.push(self.parse_cast_expression()?); } diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index 9637eabbdb..b82a908772 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -228,8 +228,7 @@ mod tests { // & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= assert_eq!( output, - r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test - /* test */ // "# + r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test /* test */ // "# ); } From 5bfca36fc717326f931bbfd7757e3c50d8685bf6 Mon Sep 17 00:00:00 2001 From: collin Date: Tue, 30 Mar 2021 14:28:22 -0700 Subject: [PATCH 046/108] fix array indexing bug and add test --- asg/src/expression/array_access.rs | 2 +- compiler/tests/array/mod.rs | 41 ++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/asg/src/expression/array_access.rs b/asg/src/expression/array_access.rs index fdf0d185c6..ad353ffaf6 100644 --- a/asg/src/expression/array_access.rs +++ b/asg/src/expression/array_access.rs @@ -111,7 +111,7 @@ impl<'a> FromAst<'a, leo_ast::ArrayAccessExpression> for ArrayAccessExpression<' .map(|x| x.int().map(|x| x.to_usize()).flatten()) .flatten() { - if index > array_len { + if index >= array_len { return Err(AsgConvertError::array_index_out_of_bounds( index, &array.span().cloned().unwrap_or_default(), diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index ca241eb93e..7acbd1af2f 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -577,6 +577,21 @@ fn test_array_index_bounds_fail() { expect_compiler_error(program); } +#[test] +fn test_const_array_index_bounds_fail() { + let program_string = r#" + function main() { + let b = [1u8, 2, 3, 4]; + const i: u32 = 4; + + console.assert(2 == b[i]); + } + "#; + let error = parse_program(program_string).err().unwrap(); + + expect_asg_error(error); +} + #[test] fn test_array_range_index() { let program_string = r#" @@ -635,21 +650,31 @@ fn test_array_range_index_full_dyn() { } #[test] -fn test_array_range_index_fail_bounds() { +fn test_array_range_index_out_of_bounds_fail() { let program_string = r#" - function main(i: u32, y: u32) { + function main() { let b = [1u8, 2, 3, 4]; console.assert([1, 2] == b[3..5]); } "#; - let input_string = r#" - [main] - i: u32 = 2; - "#; - let err = parse_program_with_input(program_string, input_string).is_err(); + let error = parse_program(program_string).err().unwrap(); - assert!(err); + expect_asg_error(error); +} + +#[test] +fn test_array_range_index_invalid_bounds_fail() { + let program_string = r#" + function main() { + let b = [1u8, 2, 3, 4]; + + console.assert([1, 2] == b[2..1]); + } + "#; + let error = parse_program(program_string).err().unwrap(); + + expect_asg_error(error); } #[test] From 144f3ee4395e94bab43e72914aced3ee32b1584a Mon Sep 17 00:00:00 2001 From: gluax Date: Tue, 30 Mar 2021 19:13:17 -0400 Subject: [PATCH 047/108] fix test_tokenizer --- parser/src/tokenizer/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index b82a908772..0c21c93eaa 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -228,7 +228,10 @@ mod tests { // & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= assert_eq!( output, - r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test /* test */ // "# + r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test + + /* test */ // + "# ); } From 25ae030e1a61e4a1e473df11558fdf6908a91351 Mon Sep 17 00:00:00 2001 From: Protryon Date: Tue, 30 Mar 2021 16:24:11 -0700 Subject: [PATCH 048/108] fix tokenizer test --- parser/src/tokenizer/mod.rs | 3 ++- parser/src/tokenizer/token.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/parser/src/tokenizer/mod.rs b/parser/src/tokenizer/mod.rs index b82a908772..9637eabbdb 100644 --- a/parser/src/tokenizer/mod.rs +++ b/parser/src/tokenizer/mod.rs @@ -228,7 +228,8 @@ mod tests { // & &= | |= ^ ^= ~ << <<= >> >>= >>> >>>= % %= ||= &&= assert_eq!( output, - r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test /* test */ // "# + r#""test" "test{}test" "test{}" "{}test" "test{" "test}" "test{test" "test}test" "te{{}}" aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8 test_ident 12345 address as bool circuit const else false field for function group i128 i64 i32 i16 i8 if import in input let mut return static string test true u128 u64 u32 u16 u8 self Self console ! != && ( ) * ** **= *= + += , - -= -> _ . .. ... / /= : :: ; < <= = == > >= @ [ ] { { } } || ? // test + /* test */ // "# ); } diff --git a/parser/src/tokenizer/token.rs b/parser/src/tokenizer/token.rs index d0df534594..df774c4a82 100644 --- a/parser/src/tokenizer/token.rs +++ b/parser/src/tokenizer/token.rs @@ -199,7 +199,7 @@ impl fmt::Display for Token { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Token::*; match self { - CommentLine(s) => writeln!(f, "{}", s), + CommentLine(s) => write!(f, "{}", s), CommentBlock(s) => write!(f, "{}", s), FormattedString(parts) => { // todo escapes From 7fea0533fa67e6370a20b5532e03ff0c98be6eb1 Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 31 Mar 2021 17:39:33 +0300 Subject: [PATCH 049/108] removed unused code in leo-package --- package/src/errors/imports/directory.rs | 20 +--------------- package/src/errors/inputs/directory.rs | 6 ----- package/src/errors/inputs/input.rs | 8 +------ package/src/errors/inputs/state.rs | 8 +------ package/src/errors/outputs/checksum.rs | 8 +------ package/src/errors/outputs/circuit.rs | 8 +------ package/src/errors/outputs/directory.rs | 20 +--------------- package/src/errors/outputs/proof.rs | 8 +------ package/src/errors/outputs/proving_key.rs | 8 +------ .../src/errors/outputs/verification_key.rs | 16 ++++++------- package/src/errors/package.rs | 8 +------ package/src/errors/root/gitignore.rs | 8 ------- package/src/errors/root/readme.rs | 8 ------- package/src/errors/root/zip.rs | 12 +--------- package/src/errors/source/lib.rs | 8 ------- package/src/errors/source/main.rs | 8 ------- package/src/imports/directory.rs | 23 ++++++++++--------- 17 files changed, 29 insertions(+), 156 deletions(-) diff --git a/package/src/errors/imports/directory.rs b/package/src/errors/imports/directory.rs index 05e6cfadf2..e027babdec 100644 --- a/package/src/errors/imports/directory.rs +++ b/package/src/errors/imports/directory.rs @@ -14,34 +14,16 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{ffi::OsString, fs::FileType, io}; +use std::{ffi::OsString, io}; #[derive(Debug, Error)] pub enum ImportsDirectoryError { #[error("creating: {}", _0)] Creating(io::Error), - #[error("file entry getting: {}", _0)] - GettingFileEntry(io::Error), - - #[error("file {:?} extension getting", _0)] - GettingFileExtension(OsString), - - #[error("file {:?} type getting: {}", _0, _1)] - GettingFileType(OsString, io::Error), - #[error("package {:?} does not exist as an import", _0)] ImportDoesNotExist(OsString), - #[error("invalid file {:?} extension: {:?}", _0, _1)] - InvalidFileExtension(OsString, OsString), - - #[error("invalid file {:?} type: {:?}", _0, _1)] - InvalidFileType(OsString, FileType), - - #[error("reading: {}", _0)] - Reading(io::Error), - #[error("removing: {}", _0)] Removing(io::Error), } diff --git a/package/src/errors/inputs/directory.rs b/package/src/errors/inputs/directory.rs index ee93d8c6d6..0a36e53836 100644 --- a/package/src/errors/inputs/directory.rs +++ b/package/src/errors/inputs/directory.rs @@ -26,9 +26,6 @@ pub enum InputsDirectoryError { #[error("file entry getting: {}", _0)] GettingFileEntry(io::Error), - #[error("file {:?} extension getting", _0)] - GettingFileExtension(OsString), - #[error("file {:?} name getting", _0)] GettingFileName(OsString), @@ -38,9 +35,6 @@ pub enum InputsDirectoryError { #[error("{}", _0)] InputFileError(#[from] InputFileError), - #[error("invalid file {:?} extension: {:?}", _0, _1)] - InvalidFileExtension(String, OsString), - #[error("invalid file {:?} type: {:?}", _0, _1)] InvalidFileType(OsString, FileType), diff --git a/package/src/errors/inputs/input.rs b/package/src/errors/inputs/input.rs index 659fcf32a3..0dbbbb0a0c 100644 --- a/package/src/errors/inputs/input.rs +++ b/package/src/errors/inputs/input.rs @@ -14,21 +14,15 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum InputFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for InputFileError { diff --git a/package/src/errors/inputs/state.rs b/package/src/errors/inputs/state.rs index 8d56253b46..e944f93469 100644 --- a/package/src/errors/inputs/state.rs +++ b/package/src/errors/inputs/state.rs @@ -14,21 +14,15 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum StateFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for StateFileError { diff --git a/package/src/errors/outputs/checksum.rs b/package/src/errors/outputs/checksum.rs index e2a6bd4375..7d52981bd8 100644 --- a/package/src/errors/outputs/checksum.rs +++ b/package/src/errors/outputs/checksum.rs @@ -14,24 +14,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum ChecksumFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for ChecksumFileError { diff --git a/package/src/errors/outputs/circuit.rs b/package/src/errors/outputs/circuit.rs index ce006c88f2..69b172c05d 100644 --- a/package/src/errors/outputs/circuit.rs +++ b/package/src/errors/outputs/circuit.rs @@ -14,24 +14,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum CircuitFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for CircuitFileError { diff --git a/package/src/errors/outputs/directory.rs b/package/src/errors/outputs/directory.rs index 2e16be7e39..8945526cfa 100644 --- a/package/src/errors/outputs/directory.rs +++ b/package/src/errors/outputs/directory.rs @@ -14,31 +14,13 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{ffi::OsString, fs::FileType, io}; +use std::io; #[derive(Debug, Error)] pub enum OutputsDirectoryError { #[error("creating: {}", _0)] Creating(io::Error), - #[error("file entry getting: {}", _0)] - GettingFileEntry(io::Error), - - #[error("file {:?} extension getting", _0)] - GettingFileExtension(OsString), - - #[error("file {:?} type getting: {}", _0, _1)] - GettingFileType(OsString, io::Error), - - #[error("invalid file {:?} extension: {:?}", _0, _1)] - InvalidFileExtension(OsString, OsString), - - #[error("invalid file {:?} type: {:?}", _0, _1)] - InvalidFileType(OsString, FileType), - - #[error("reading: {}", _0)] - Reading(io::Error), - #[error("removing: {}", _0)] Removing(io::Error), } diff --git a/package/src/errors/outputs/proof.rs b/package/src/errors/outputs/proof.rs index 461a3ab259..adce5b7bf5 100644 --- a/package/src/errors/outputs/proof.rs +++ b/package/src/errors/outputs/proof.rs @@ -14,24 +14,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum ProofFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for ProofFileError { diff --git a/package/src/errors/outputs/proving_key.rs b/package/src/errors/outputs/proving_key.rs index d78e62aec4..6431af92fd 100644 --- a/package/src/errors/outputs/proving_key.rs +++ b/package/src/errors/outputs/proving_key.rs @@ -14,24 +14,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum ProvingKeyFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for ProvingKeyFileError { diff --git a/package/src/errors/outputs/verification_key.rs b/package/src/errors/outputs/verification_key.rs index 51398e630c..bcf3e8de66 100644 --- a/package/src/errors/outputs/verification_key.rs +++ b/package/src/errors/outputs/verification_key.rs @@ -14,27 +14,25 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum VerificationKeyFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - + // #[error("creating: {}", _0)] + // Creating(io::Error), #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), + // #[error("Verification key file was corrupted")] + // IncorrectVerificationKey, - #[error("Verification key file was corrupted")] - IncorrectVerificationKey, - - #[error("writing: {}", _0)] - Writing(io::Error), + // #[error("writing: {}", _0)] + // Writing(io::Error), } impl From for VerificationKeyFileError { diff --git a/package/src/errors/package.rs b/package/src/errors/package.rs index f0a07ea1ee..47f4808924 100644 --- a/package/src/errors/package.rs +++ b/package/src/errors/package.rs @@ -13,24 +13,18 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{ffi::OsString, io}; +use std::ffi::OsString; #[derive(Debug, Error)] pub enum PackageError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("`{}` creating: {}", _0, _1)] - Creating(&'static str, io::Error), - #[error("Failed to initialize package {:?} ({:?})", _0, _1)] FailedToInitialize(String, OsString), #[error("Invalid project name: {:?}", _0)] InvalidPackageName(String), - - #[error("`{}` metadata: {}", _0, _1)] - Removing(&'static str, io::Error), } impl From for PackageError { diff --git a/package/src/errors/root/gitignore.rs b/package/src/errors/root/gitignore.rs index bb8b5d2bca..bf047ddabb 100644 --- a/package/src/errors/root/gitignore.rs +++ b/package/src/errors/root/gitignore.rs @@ -14,18 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::io; - #[derive(Debug, Error)] pub enum GitignoreError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - - #[error("creating: {}", _0)] - Creating(io::Error), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for GitignoreError { diff --git a/package/src/errors/root/readme.rs b/package/src/errors/root/readme.rs index c123ddd826..f5d99216c5 100644 --- a/package/src/errors/root/readme.rs +++ b/package/src/errors/root/readme.rs @@ -14,19 +14,11 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::io; - #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Error)] pub enum READMEError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - - #[error("creating: {}", _0)] - Creating(io::Error), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for READMEError { diff --git a/package/src/errors/root/zip.rs b/package/src/errors/root/zip.rs index e9a9c15b82..af9f4e231b 100644 --- a/package/src/errors/root/zip.rs +++ b/package/src/errors/root/zip.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::{io, path::PathBuf}; -use walkdir::Error as WalkDirError; +use std::path::PathBuf; use zip::result::ZipError; #[derive(Debug, Error)] @@ -23,21 +22,12 @@ pub enum ZipFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - #[error("writing: {}", _0)] - Writing(io::Error), - - #[error("{}", _0)] - WalkDirError(#[from] WalkDirError), - #[error("{}", _0)] ZipError(#[from] ZipError), } diff --git a/package/src/errors/source/lib.rs b/package/src/errors/source/lib.rs index 6b754373e7..149257085c 100644 --- a/package/src/errors/source/lib.rs +++ b/package/src/errors/source/lib.rs @@ -14,18 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::io; - #[derive(Debug, Error)] pub enum LibraryFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - - #[error("creating: {}", _0)] - Creating(io::Error), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for LibraryFileError { diff --git a/package/src/errors/source/main.rs b/package/src/errors/source/main.rs index 07460b50e2..fc1de8d998 100644 --- a/package/src/errors/source/main.rs +++ b/package/src/errors/source/main.rs @@ -14,18 +14,10 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use std::io; - #[derive(Debug, Error)] pub enum MainFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - - #[error("creating: {}", _0)] - Creating(io::Error), - - #[error("writing: {}", _0)] - Writing(io::Error), } impl From for MainFileError { diff --git a/package/src/imports/directory.rs b/package/src/imports/directory.rs index a1d7e850ea..0d1f2be802 100644 --- a/package/src/imports/directory.rs +++ b/package/src/imports/directory.rs @@ -33,19 +33,20 @@ impl ImportsDirectory { fs::create_dir_all(&path).map_err(ImportsDirectoryError::Creating) } - /// Removes the directory at the provided path. - pub fn remove(path: &Path) -> Result<(), ImportsDirectoryError> { - let mut path = Cow::from(path); - if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) { - path.to_mut().push(IMPORTS_DIRECTORY_NAME); - } + // TODO: REMOVE + // /// Removes the directory at the provided path. + // pub fn remove(path: &Path) -> Result<(), ImportsDirectoryError> { + // let mut path = Cow::from(path); + // if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) { + // path.to_mut().push(IMPORTS_DIRECTORY_NAME); + // } - if path.exists() { - fs::remove_dir_all(&path).map_err(ImportsDirectoryError::Removing)?; - } + // if path.exists() { + // fs::remove_dir_all(&path).map_err(ImportsDirectoryError::Removing)?; + // } - Ok(()) - } + // Ok(()) + // } /// Removes an imported package in the imports directory at the provided path. pub fn remove_import(path: &Path, package_name: &str) -> Result<(), ImportsDirectoryError> { From 41600d02619dd693929dac8aeee87e96a5224c8a Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 31 Mar 2021 18:06:22 +0300 Subject: [PATCH 050/108] removed unused errors in compiler --- compiler/src/errors/compiler.rs | 27 +-------- compiler/src/errors/expression.rs | 83 +--------------------------- compiler/src/errors/function.rs | 12 ---- compiler/src/errors/import.rs | 24 +------- compiler/src/errors/statement.rs | 39 ------------- compiler/src/errors/value/address.rs | 16 ------ compiler/src/errors/value/field.rs | 6 -- compiler/src/errors/value/integer.rs | 40 +------------- compiler/src/errors/value/value.rs | 20 +------ package/src/imports/directory.rs | 15 ----- 10 files changed, 6 insertions(+), 276 deletions(-) diff --git a/compiler/src/errors/compiler.rs b/compiler/src/errors/compiler.rs index f9c5f9919e..f66cdd488a 100644 --- a/compiler/src/errors/compiler.rs +++ b/compiler/src/errors/compiler.rs @@ -14,16 +14,14 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::errors::{FunctionError, ImportError, OutputBytesError, OutputFileError}; +use crate::errors::FunctionError; use leo_asg::{AsgConvertError, FormattedError}; use leo_ast::{CanonicalizeError, LeoError}; -use leo_imports::ImportParserError; use leo_input::InputParserError; use leo_parser::SyntaxError; use leo_state::LocalDataVerificationError; -use bincode::Error as SerdeError; -use std::{ffi::OsString, path::PathBuf}; +use std::path::PathBuf; #[derive(Debug, Error)] pub enum CompilerError { @@ -33,12 +31,6 @@ pub enum CompilerError { #[error("{}", _0)] AsgPassError(FormattedError), - #[error("{}", _0)] - ImportError(#[from] ImportError), - - #[error("{}", _0)] - ImportParserError(#[from] ImportParserError), - #[error("{}", _0)] InputParserError(#[from] InputParserError), @@ -51,30 +43,15 @@ pub enum CompilerError { #[error("Cannot read from the provided file path '{:?}': {}", _0, _1)] FileReadError(PathBuf, std::io::Error), - #[error("Cannot parse file string `{:?}`", _0)] - FileStringError(OsString), - #[error("{}", _0)] LocalDataVerificationError(#[from] LocalDataVerificationError), - #[error("`main` function not found")] - NoMain, - #[error("`main` must be a function")] NoMainFunction, #[error("Failed to find input files for the current test")] NoTestInput, - #[error("{}", _0)] - OutputError(#[from] OutputFileError), - - #[error("{}", _0)] - OutputStringError(#[from] OutputBytesError), - - #[error("{}", _0)] - SerdeError(#[from] SerdeError), - #[error("{}", _0)] AsgConvertError(#[from] AsgConvertError), diff --git a/compiler/src/errors/expression.rs b/compiler/src/errors/expression.rs index e472688f5b..e093b5dd2f 100644 --- a/compiler/src/errors/expression.rs +++ b/compiler/src/errors/expression.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::errors::{AddressError, BooleanError, FieldError, FunctionError, GroupError, IntegerError, ValueError}; -use leo_ast::{ArrayDimensions, FormattedError, Identifier, LeoError, PositiveNumber, Span}; +use leo_ast::{FormattedError, Identifier, LeoError, Span}; use snarkvm_r1cs::SynthesisError; #[derive(Debug, Error)] @@ -115,24 +115,6 @@ impl ExpressionError { Self::new_from_span(message, span) } - pub fn invalid_dimensions(expected: &ArrayDimensions, actual: &ArrayDimensions, span: &Span) -> Self { - let message = format!( - "expected array dimensions {}, found array dimensions {}", - expected, actual - ); - - Self::new_from_span(message, span) - } - - pub fn invalid_first_dimension(expected: &PositiveNumber, actual: &PositiveNumber, span: &Span) -> Self { - let message = format!( - "expected array dimension {}, found array dimension {}", - expected, actual - ); - - Self::new_from_span(message, span) - } - pub fn invalid_index(actual: String, span: &Span) -> Self { let message = format!("index must resolve to an integer, found `{}`", actual); @@ -145,48 +127,18 @@ impl ExpressionError { Self::new_from_span(message, span) } - pub fn invalid_spread(actual: String, span: &Span) -> Self { - let message = format!("spread should contain an array, found `{}`", actual); - - Self::new_from_span(message, span) - } - - pub fn invalid_member_access(member: String, span: &Span) -> Self { - let message = format!("non-static member `{}` must be accessed using `.` syntax", member); - - Self::new_from_span(message, span) - } - pub fn invalid_static_access(member: String, span: &Span) -> Self { let message = format!("static member `{}` must be accessed using `::` syntax", member); Self::new_from_span(message, span) } - pub fn function_no_return(function: String, span: &Span) -> Self { - let message = format!("inline function call to `{}` did not return", function); - - Self::new_from_span(message, span) - } - - pub fn self_keyword(span: &Span) -> Self { - let message = "cannot call keyword `Self` outside of a circuit function".to_string(); - - Self::new_from_span(message, span) - } - pub fn undefined_array(actual: String, span: &Span) -> Self { let message = format!("array `{}` must be declared before it is used in an expression", actual); Self::new_from_span(message, span) } - pub fn undefined_tuple(actual: String, span: &Span) -> Self { - let message = format!("tuple `{}` must be declared before it is used in an expression", actual); - - Self::new_from_span(message, span) - } - pub fn undefined_circuit(actual: String, span: &Span) -> Self { let message = format!( "circuit `{}` must be declared before it is used in an expression", @@ -196,21 +148,6 @@ impl ExpressionError { Self::new_from_span(message, span) } - pub fn undefined_first_dimension(span: &Span) -> Self { - let message = "the first dimension of the array must be a number".to_string(); - - Self::new_from_span(message, span) - } - - pub fn undefined_function(function: String, span: &Span) -> Self { - let message = format!( - "function `{}` must be declared before it is used in an inline expression", - function - ); - - Self::new_from_span(message, span) - } - pub fn undefined_identifier(identifier: Identifier) -> Self { let message = format!("Cannot find value `{}` in this scope", identifier.name); @@ -222,22 +159,4 @@ impl ExpressionError { Self::new_from_span(message, span) } - - pub fn undefined_static_access(circuit: String, member: String, span: &Span) -> Self { - let message = format!("Circuit `{}` has no static member `{}`", circuit, member); - - Self::new_from_span(message, span) - } - - pub fn unexpected_array(expected: String, span: &Span) -> Self { - let message = format!("expected type `{}`, found array with elements", expected); - - Self::new_from_span(message, span) - } - - pub fn unexpected_tuple(expected: String, actual: String, span: &Span) -> Self { - let message = format!("expected type `{}`, found tuple with values `{}`", expected, actual); - - Self::new_from_span(message, span) - } } diff --git a/compiler/src/errors/function.rs b/compiler/src/errors/function.rs index 791c654377..d4ab00c0d5 100644 --- a/compiler/src/errors/function.rs +++ b/compiler/src/errors/function.rs @@ -128,18 +128,6 @@ impl FunctionError { Self::new_from_span(message, span) } - pub fn return_arguments_length(expected: usize, actual: usize, span: &Span) -> Self { - let message = format!("function expected {} returns, found {} returns", expected, actual); - - Self::new_from_span(message, span) - } - - pub fn return_argument_type(expected: String, actual: String, span: &Span) -> Self { - let message = format!("Expected function return type `{}`, found `{}`", expected, actual); - - Self::new_from_span(message, span) - } - pub fn input_not_found(expected: String, span: &Span) -> Self { let message = format!("main function input {} not found", expected); diff --git a/compiler/src/errors/import.rs b/compiler/src/errors/import.rs index dde6ce1644..022ec5d1b9 100644 --- a/compiler/src/errors/import.rs +++ b/compiler/src/errors/import.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use leo_ast::{FormattedError, Identifier, ImportSymbol, LeoError, Span}; +use leo_ast::{FormattedError, LeoError}; #[derive(Debug, Error)] pub enum ImportError { @@ -23,25 +23,3 @@ pub enum ImportError { } impl LeoError for ImportError {} - -impl ImportError { - fn new_from_span(message: String, span: &Span) -> Self { - ImportError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn unknown_package(identifier: Identifier) -> Self { - let message = format!( - "cannot find imported package `{}` in source files or import directory", - identifier.name - ); - - Self::new_from_span(message, &identifier.span) - } - - pub fn unknown_symbol(symbol: ImportSymbol, file: String) -> Self { - let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file); - let error = FormattedError::new_from_span(message, &symbol.span); - - ImportError::Error(error) - } -} diff --git a/compiler/src/errors/statement.rs b/compiler/src/errors/statement.rs index 6a7d49ca35..fd42cbd5d8 100644 --- a/compiler/src/errors/statement.rs +++ b/compiler/src/errors/statement.rs @@ -49,12 +49,6 @@ impl StatementError { StatementError::Error(FormattedError::new_from_span(message, span)) } - pub fn arguments_type(expected: &Type, actual: &Type, span: &Span) -> Self { - let message = format!("expected return argument type `{}`, found type `{}`", expected, actual); - - Self::new_from_span(message, span) - } - pub fn array_assign_index(span: &Span) -> Self { let message = "Cannot assign single index to array of values".to_string(); @@ -103,24 +97,6 @@ impl StatementError { Self::new_from_span(message, span) } - pub fn immutable_assign(name: String, span: &Span) -> Self { - let message = format!("Cannot assign to immutable variable `{}`", name); - - Self::new_from_span(message, span) - } - - pub fn immutable_circuit_function(name: String, span: &Span) -> Self { - let message = format!("Cannot mutate circuit function, `{}`", name); - - Self::new_from_span(message, span) - } - - pub fn immutable_circuit_variable(name: String, span: &Span) -> Self { - let message = format!("Circuit member variable `{}` is immutable", name); - - Self::new_from_span(message, span) - } - pub fn indicator_calculation(name: String, span: &Span) -> Self { let message = format!( "Constraint system failed to evaluate branch selection indicator `{}`", @@ -139,15 +115,6 @@ impl StatementError { Self::new_from_span(message, span) } - pub fn invalid_number_of_returns(expected: usize, actual: usize, span: &Span) -> Self { - let message = format!( - "Function return statement expected {} return values, found {} values", - expected, actual - ); - - Self::new_from_span(message, span) - } - pub fn multiple_definition(value: String, span: &Span) -> Self { let message = format!("cannot assign multiple variables to a single value: {}", value,); @@ -194,12 +161,6 @@ impl StatementError { Self::new_from_span(message, span) } - pub fn tuple_type(type_: String, span: &Span) -> Self { - let message = format!("Expected tuple type, found type `{}`", type_); - - Self::new_from_span(message, span) - } - pub fn unassigned(span: &Span) -> Self { let message = "Expected assignment of return values for expression".to_string(); diff --git a/compiler/src/errors/value/address.rs b/compiler/src/errors/value/address.rs index 73a499705c..2b8d4d8022 100644 --- a/compiler/src/errors/value/address.rs +++ b/compiler/src/errors/value/address.rs @@ -16,7 +16,6 @@ use leo_ast::{FormattedError, LeoError, Span}; use snarkvm_dpc::AccountError; -use snarkvm_r1cs::SynthesisError; #[derive(Debug, Error)] pub enum AddressError { @@ -37,21 +36,6 @@ impl AddressError { Self::new_from_span(message, span) } - pub fn cannot_enforce(operation: String, error: SynthesisError, span: &Span) -> Self { - let message = format!( - "the address operation `{:?}` failed due to the synthesis error `{}`", - operation, error, - ); - - Self::new_from_span(message, span) - } - - pub fn cannot_evaluate(operation: String, span: &Span) -> Self { - let message = format!("no implementation found for `{}`", operation); - - Self::new_from_span(message, span) - } - pub fn invalid_address(actual: String, span: &Span) -> Self { let message = format!("expected address input type, found `{}`", actual); diff --git a/compiler/src/errors/value/field.rs b/compiler/src/errors/value/field.rs index 87de99b995..9ec8a5f152 100644 --- a/compiler/src/errors/value/field.rs +++ b/compiler/src/errors/value/field.rs @@ -62,10 +62,4 @@ impl FieldError { Self::new_from_span(message, span) } - - pub fn synthesis_error(error: SynthesisError, span: &Span) -> Self { - let message = format!("compilation failed due to field synthesis error `{:?}`", error); - - Self::new_from_span(message, span) - } } diff --git a/compiler/src/errors/value/integer.rs b/compiler/src/errors/value/integer.rs index 8fecda685c..457575b1dc 100644 --- a/compiler/src/errors/value/integer.rs +++ b/compiler/src/errors/value/integer.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use leo_ast::{FormattedError, IntegerType, LeoError, Span, Type}; +use leo_ast::{FormattedError, LeoError, Span}; use snarkvm_gadgets::errors::SignedIntegerError; use snarkvm_r1cs::SynthesisError; @@ -32,30 +32,12 @@ impl IntegerError { IntegerError::Error(FormattedError::new_from_span(message, span)) } - pub fn cannot_enforce(operation: String, error: SynthesisError, span: &Span) -> Self { - let message = format!( - "the integer operation `{}` failed due to the synthesis error `{:?}`", - operation, error, - ); - - Self::new_from_span(message, span) - } - pub fn signed(error: SignedIntegerError, span: &Span) -> Self { let message = format!("integer operation failed due to the signed integer error `{:?}`", error); Self::new_from_span(message, span) } - pub fn signed_error(operation: String, error: SignedIntegerError, span: &Span) -> Self { - let message = format!( - "the integer operation `{}` failed due to the signed integer error `{:?}`", - operation, error - ); - - Self::new_from_span(message, span) - } - pub fn synthesis(error: SynthesisError, span: &Span) -> Self { let message = format!("integer operation failed due to the synthesis error `{}`", error); @@ -77,32 +59,12 @@ impl IntegerError { Self::new_from_span(message, span) } - pub fn invalid_index(span: &Span) -> Self { - let message = - "index must be a constant value unsigned integer. allocated indices produce a circuit of unknown size" - .to_string(); - - Self::new_from_span(message, span) - } - pub fn invalid_integer(actual: String, span: &Span) -> Self { let message = format!("failed to parse `{}` as expected integer type", actual); Self::new_from_span(message, span) } - pub fn invalid_integer_type(expected: &IntegerType, actual: &IntegerType, span: &Span) -> Self { - let message = format!("expected integer type {} found integer type {}", expected, actual); - - Self::new_from_span(message, span) - } - - pub fn invalid_type(actual: &Type, span: &Span) -> Self { - let message = format!("expected type {}, found type IntegerType", actual); - - Self::new_from_span(message, span) - } - pub fn missing_integer(expected: String, span: &Span) -> Self { let message = format!("expected integer input `{}` not found", expected); diff --git a/compiler/src/errors/value/value.rs b/compiler/src/errors/value/value.rs index 90b9ef29b2..bd34b788c8 100644 --- a/compiler/src/errors/value/value.rs +++ b/compiler/src/errors/value/value.rs @@ -15,7 +15,7 @@ // along with the Leo library. If not, see . use crate::errors::{AddressError, BooleanError, FieldError, GroupError, IntegerError}; -use leo_ast::{FormattedError, LeoError, Span}; +use leo_ast::{FormattedError, LeoError}; #[derive(Debug, Error)] pub enum ValueError { @@ -39,21 +39,3 @@ pub enum ValueError { } impl LeoError for ValueError {} - -impl ValueError { - fn new_from_span(message: String, span: &Span) -> Self { - ValueError::Error(FormattedError::new_from_span(message, span)) - } - - pub fn implicit(value: String, span: &Span) -> Self { - let message = format!("explicit type needed for `{}`", value); - - Self::new_from_span(message, span) - } - - pub fn implicit_group(span: &Span) -> Self { - let message = "group coordinates should be in (x, y)group format".to_string(); - - Self::new_from_span(message, span) - } -} diff --git a/package/src/imports/directory.rs b/package/src/imports/directory.rs index 0d1f2be802..1f01597d2e 100644 --- a/package/src/imports/directory.rs +++ b/package/src/imports/directory.rs @@ -33,21 +33,6 @@ impl ImportsDirectory { fs::create_dir_all(&path).map_err(ImportsDirectoryError::Creating) } - // TODO: REMOVE - // /// Removes the directory at the provided path. - // pub fn remove(path: &Path) -> Result<(), ImportsDirectoryError> { - // let mut path = Cow::from(path); - // if path.is_dir() && !path.ends_with(IMPORTS_DIRECTORY_NAME) { - // path.to_mut().push(IMPORTS_DIRECTORY_NAME); - // } - - // if path.exists() { - // fs::remove_dir_all(&path).map_err(ImportsDirectoryError::Removing)?; - // } - - // Ok(()) - // } - /// Removes an imported package in the imports directory at the provided path. pub fn remove_import(path: &Path, package_name: &str) -> Result<(), ImportsDirectoryError> { let mut path = Cow::from(path); From ed8ff4468cddaba0a555ccde77bc803da1f43da7 Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 31 Mar 2021 18:58:29 +0300 Subject: [PATCH 051/108] ast and imports a bit --- ast/src/common/array_dimensions.rs | 12 ------------ imports/src/errors/import_parser.rs | 24 +----------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/ast/src/common/array_dimensions.rs b/ast/src/common/array_dimensions.rs index b0079c902f..4dc7188464 100644 --- a/ast/src/common/array_dimensions.rs +++ b/ast/src/common/array_dimensions.rs @@ -26,18 +26,6 @@ use std::fmt; pub struct ArrayDimensions(pub Vec); impl ArrayDimensions { - /// - /// Creates a new `PositiveNumber` from the given `usize` and `Span`. - /// Appends the new `PositiveNumber` to the array dimensions. - /// - pub fn push_usize(&mut self, number: usize) { - let positive_number = PositiveNumber { - value: number.to_string().into(), - }; - - self.0.push(positive_number) - } - /// /// Appends a vector of array dimensions to the self array dimensions. /// diff --git a/imports/src/errors/import_parser.rs b/imports/src/errors/import_parser.rs index 87a3e8b03c..0c04467403 100644 --- a/imports/src/errors/import_parser.rs +++ b/imports/src/errors/import_parser.rs @@ -15,15 +15,12 @@ // along with the Leo library. If not, see . use leo_asg::AsgConvertError; use leo_ast::{FormattedError, Identifier, LeoError, Span}; -use leo_parser::{DeprecatedError, SyntaxError}; +use leo_parser::SyntaxError; use std::{io, path::Path}; #[derive(Debug, Error)] pub enum ImportParserError { - #[error("{}", _0)] - DeprecatedError(#[from] DeprecatedError), - #[error("{}", _0)] Error(#[from] FormattedError), @@ -40,7 +37,6 @@ impl Into for ImportParserError { match self { ImportParserError::Error(x) => AsgConvertError::ImportError(x), ImportParserError::SyntaxError(x) => x.into(), - ImportParserError::DeprecatedError(x) => AsgConvertError::SyntaxError(SyntaxError::DeprecatedError(x)), ImportParserError::AsgConvertError(x) => x, } } @@ -66,15 +62,6 @@ impl ImportParserError { Self::new_from_span(message, span) } - /// - /// A core package name has been imported twice. - /// - pub fn duplicate_core_package(identifier: Identifier) -> Self { - let message = format!("Duplicate core_package import `{}`.", identifier.name); - - Self::new_from_span(message, &identifier.span) - } - /// /// Failed to convert a file path into an os string. /// @@ -106,15 +93,6 @@ impl ImportParserError { Self::new_from_span(message, span) } - /// - /// Failed to import all symbols at a package path. - /// - pub fn star(path: &Path, span: &Span) -> Self { - let message = format!("Cannot import `*` from path `{:?}`.", path); - - Self::new_from_span(message, span) - } - /// /// Failed to find a library file for the current package. /// From ba53d143ee75a0d016a768f05f44cebba3d5f6aa Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 31 Mar 2021 09:57:02 -0700 Subject: [PATCH 052/108] cargo clippy --- grammar/src/main.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/grammar/src/main.rs b/grammar/src/main.rs index defb8ce9ef..6c70568ded 100644 --- a/grammar/src/main.rs +++ b/grammar/src/main.rs @@ -77,21 +77,21 @@ impl<'a> Processor<'a> { /// Main function for this struct. /// Goes through each line and transforms it into proper markdown. fn process(&mut self) -> Result<()> { - let mut lines = self.grammar.lines(); + let lines = self.grammar.lines(); let mut prev = ""; - while let Some(line) = lines.next() { + for line in lines { self.line += 1; // code block in comment (not highlighted as abnf) - if line.starts_with("; ") { + if let Some(code) = line.strip_prefix("; ") { self.enter_scope(Scope::Code)?; - self.append_str(&line[3..]); + self.append_str(code); // just comment. end of code block - } else if line.starts_with("; ") { + } else if let Some(code) = line.strip_prefix("; ") { self.enter_scope(Scope::Free)?; - self.append_str(&line[2..]); + self.append_str(code); // horizontal rule - section separator } else if line.starts_with(";;;;;;;;;;") { @@ -99,24 +99,24 @@ impl<'a> Processor<'a> { self.append_str("\n--------\n"); // empty line in comment. end of code block - } else if line.starts_with(";") { + } else if line.starts_with(';') { self.enter_scope(Scope::Free)?; self.append_str("\n\n"); // just empty line. end of doc, start of definition - } else if line.len() == 0 { + } else if line.is_empty() { self.enter_scope(Scope::Free)?; self.append_str(""); // definition (may be multiline) } else { // if there's an equality sign and previous line was empty - if line.contains("=") && prev.len() == 0 { - let (def, _) = line.split_at(line.find("=").unwrap()); + if line.contains('=') && prev.is_empty() { + let (def, _) = line.split_at(line.find('=').unwrap()); let def = def.trim(); // try to find rule matching definition or fail - let rule = self.rules.get(&def.to_string()).map(|rule| rule.clone()).unwrap(); + let rule = self.rules.get(&def.to_string()).cloned().unwrap(); self.enter_scope(Scope::Definition(rule))?; } @@ -133,7 +133,7 @@ impl<'a> Processor<'a> { /// Append new line into output, add newline character. fn append_str(&mut self, line: &str) { self.out.push_str(line); - self.out.push_str("\n"); + self.out.push('\n'); } /// Enter new scope (definition or code block). Allows customizing @@ -166,7 +166,7 @@ impl<'a> Processor<'a> { self.append_str("```"); - if keys.len() > 0 { + if !keys.is_empty() { self.append_str(&format!("\nGo to: _{}_;\n", keys)); } } From bcb0838e0ddab69c91c5b38c57b5de9bdc023744 Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 31 Mar 2021 13:22:25 -0400 Subject: [PATCH 053/108] last bit of clippy, push grammar md it should now be in the repo --- grammar/abnf-grammar.md | 1803 +++++++++++++++++++++++++++++++++++++++ grammar/src/main.rs | 22 +- 2 files changed, 1812 insertions(+), 13 deletions(-) create mode 100644 grammar/abnf-grammar.md diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md new file mode 100644 index 0000000000..eb587deea0 --- /dev/null +++ b/grammar/abnf-grammar.md @@ -0,0 +1,1803 @@ +Leo Library + + + +Copyright (C) 2021 Aleo Systems Inc. + + + +Author: Alessandro Coglio (acoglio on GitHub) + + +-------- + + +Format Note +----------- + +The ABNF standard requires grammars to consist of lines terminated by CR LF +(i.e. carriage return followed by line feed, DOS/Windows-style), +as explained in the background on ABNF later in this file. +This file's lines are therefore terminated by CR LF. +To avoid losing this requirement across systems, +this file is marked as 'text eol=crlf' in .gitattributes: +this means that the file is textual, enabling visual diffs, +but its lines will always be terminated by CR LF on any system. + +Note that this CR LF requirement only applies to the grammar files themselves. +It does not apply to the lines of the languages described by the grammar. +ABNF grammar may describe any kinds of languages, +with any kind of line terminators, +or even without line terminators at all (e.g. for "binary" languages). + + +-------- + + +Introduction +------------ + +This file contains an initial draft of +a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. +Background on ABNF is provided later in this file. + +The initial motivation for creating an ABNF grammar of Leo was that +we have a formally verified parser of ABNF grammars +(at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; +also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) +which we have used to parse this ABNF grammar of Leo +into a formal representation, in the ACL2 theorem prover, +of the Leo concrete syntax. +The parsing of this grammar file into an ACL2 representation +happens every time the ACL2 formalization of Leo is built. + +In addition to that initial motivation, +this ABNF grammar has now the additional and primary purpose of +providing an official definition of the syntax of Leo +that is both human-readable and machine-readable. +This grammar will be part of the (upcoming) Leo language reference, +of the Leo Language Formal Specification +(i.e. the LaTeX document in the leo-semantics repo), +and of the ACL2 formalization of Leo (which was the initial motivation). +It has also been suggested that it may be used to generate tests. + + +-------- + + +Background on ABNF +------------------ + +ABNF is an Internet standard: +see https://www.rfc-editor.org/info/rfc5234 +and https://www.rfc-editor.org/info/rfc7405. +It is used to specify the syntax of JSON, HTTP, and other standards. + +The following is copied (and "un-LaTeX'd") from the aforementioned paper +(at https://www.kestrel.edu/people/coglio/vstte18.pdf). + +ABNF adds conveniences and makes slight modifications +to Backus-Naur Form (BNF), +without going beyond context-free grammars. + +Instead of BNF's angle-bracket notation for nonterminals, +ABNF uses case-insensitive names consisting of letters, digits, and dashes, +e.g. HTTP-message and IPv6address. +ABNF includes an angle-bracket notation for prose descriptions, +e.g. , +usable as last resort in the definiens of a nonterminal. + +While BNF allows arbitrary terminals, +ABNF uses only natural numbers as terminals, +and denotes them via: +(i) binary, decimal, or hexadecimal sequences, +e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A +all denote the string '1 3 10'; +(ii) binary, decimal, or hexadecimal ranges, +e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 +(an ASCII digit); +(iii) case-sensitive ASCII strings, +e.g. "Ab" denotes the string '65 98'; +and (iv) case-insensitive ASCII strings, +e.g. %i"ab", or just "ab", denotes +any string among +'65 66', +'65 98', +'97 66', and +'97 98'. +ABNF terminals in suitable sets represent ASCII or Unicode characters. + +ABNF allows repetition prefixes n*m, +where n and m are natural numbers in decimal notation; +if absent, +n defaults to 0, and +m defaults to infinity. +For example, +1*4HEXDIG denotes one to four HEXDIGs, +*3DIGIT denotes up to three DIGITs, and +1*OCTET denotes one or more OCTETs. +A single n prefix +abbreviates n*n, +e.g. 3DIGIT denotes three DIGITs. + +Instead of BNF's |, ABNF uses / to separate alternatives. +Repetition prefixes have precedence over juxtapositions, +which have precedence over /. +Round brackets group things and override the aforementioned precedence rules, +e.g. *(WSP / CRLF WSP) denotes strings +obtained by repeating, zero or more times, +either (i) a WSP or (ii) a CRLF followed by a WSP. +Square brackets also group things but make them optional, +e.g. [":" port] is equivalent to 0*1(":" port). + +Instead of BNF's ::=, ABNF uses = to define nonterminals, +and =/ to incrementally add alternatives +to previously defined nonterminals. +For example, the rule BIT = "0" / "1" +is equivalent to BIT = "0" followed by BIT =/ "1". + +The syntax of ABNF itself is formally specified in ABNF +(in Section 4 of the aforementioned RFC 5234, +after the syntax and semantics of ABNF +are informally specified in natural language +(in Sections 1, 2, and 3 of the aforementioned RFC 5234). +The syntax rules of ABNF prescribe the ASCII codes allowed for +white space (spaces and horizontal tabs), +line endings (carriage returns followed by line feeds), +and comments (semicolons to line endings). + + +-------- + + +Structure +--------- + +Language specifications often define the syntax of their languages via +(i) a lexical grammar that describes how +sequence of characters are parsed into tokens, and +(ii) a syntactic grammar that described how +tokens are parsed into expressions, statements, etc. +(The adjectives 'lexical' and 'syntactic' are +the ones used in the Java language specification; +other terms may be used by other languages, +but the essence is similar.) +The situation is sometimes more complex, +with multiple passes (e.g. Unicode escape processing in Java), +but the division between lexical and syntactic (in the sense above) stands. + +In the aforementioned language specifications, +both the lexical and syntactic grammars +are normally written in a context-free grammar notation, +augmented with natural language that may assert, for instance, +that tokenization always takes the longest sequence that constitutes a token. + +This dual structure appears to be motivated by the fact that +concerns of white space, line endings, etc. +can be handled by the lexical grammar, +allowing the syntactic grammar to focus on the more important structure. +Handling both aspects in a single context-free grammar may be unwieldy, +so having two grammars provides more clarity and readability. + +In contrast, PEG (Parsing Expression Grammar) formalisms like Pest +naturally embody a procedural interpretation +that can handle white space and tokenization in just one manageable grammar. +However, this procedural interpretaion may be sometimes +less clear and readable to humans than context-free rules. +Indeed, context-free grammar are commonly used to documentat languages. + +ABNF is a context-free grammar notation, +with no procedural interpretation, +and therefore it makes sense to define +separate lexical and syntactic ABNF grammars for Leo. +Conceptually, the two grammars define two subsequent processing phases, +as detailed below. +However, a parser implementation does not need to perform +two strictly separate phases (in fact, it typically does not), +so long as it produces the same final result. + + +-------- + + +Operator Precedence +------------------- + +We formulate the grammar rules for expressions +in a way that describes the relative precedence of operators, +as often done in language syntax specifications. + +For instance, consider the rules + + + +``` +multiplicative-expression = + exponential-expression + / multiplicative-expression "*" exponential-expression + / multiplicative-expression "/" exponential-expression +``` + + + +``` +additive-expression = + multiplicative-expression + / additive-expression "+" multiplicative-expression + / additive-expression "-" multiplicative-expression +``` + + + +this rule tells us that the additive operators '+' and '-' have +lower precedence than the multiplicative operators '*' and '/', +and that both the additive and multiplicative operators associate to the left. +This may be best understood via the examples given below. + +According to the rules, the expression + + + +``` +x + y * z +``` + + + +can only be parsed as + + + +``` + + + / \ +x * + / \ + y z +``` + + + +and not as + + + +``` + * + / \ + + z + / \ +x y +``` + + + +because a multiplicative expression cannot have an additive expression +as first sub-expression, as it would in the second tree above. + +Also according to the rules, the expression + + + +``` +x + y + z +``` + + + +can only be parsed as + + + +``` + + + / \ + + z + / \ +x y +``` + + + +and not as + + + +``` + + + / \ +x + + / \ + y z +``` + + + +because an additive expression cannot have an additive expression +as second sub-expression, as it would in the second tree above. + + +-------- + + +Naming Convention +----------------- + +For this ABNF grammar, we choose nonterminal names +that consist of complete English words, separated by dashes, +and that describe the construct the way it is in English. +For instance, we use the name 'conditional-statement' +to describe conditional statements. + +At the same time, we attempt to establish +a precise and "official" nomenclature for the Leo constructs, +by way of the nonterminal names that define their syntax. +For instance, the rule + + + +``` +group-literal = product-group-literal + / affine-group-literal +``` + + + +tells us that there are two kinds of group literals, +namely product group literals and affine group literals. +This is more precise than describing them as +integers (which are not really group elements per se), +or points (they are all points, just differently specified), +or being singletons vs. pairs (which is a bit generic). + +The only exception to the nomenclature-establishing role of the grammar +is the fact that, as discussed above, +we write the grammar rules in a way that determines +the relative precedence and the associativity of expression operators, +and that therefore we have rules like + + + +``` +unary-expression = primary-expression + / "!" unary-expression + / "-" unary-expression +``` + + + +In order to allow the recursion of the rule to stop, +we need to regard, in the grammar, a primary expression as a unary expression. +However, this is just a grammatical artifact: +ontologically, a primary expression is not really a unary expression, +because a unary expression is one that consists of +a unary operator and an operand sub-expression. +These terminological "exceptions" should be easy to identify in the rules. + + +-------- + + +Lexical Grammar +--------------- + +A Leo file is a finite sequence of Unicode characters, +represented as Unicode code points, +which are numbers in the range form 0 to 10FFFFh. +These are captured by the ABNF rule 'character' below. + +The lexical grammar defines how, conceptually, +the sequence of characters is turned into +a sequence of tokens, comments, and whitespaces. + +As stated, the lexical grammar is ambiguous. +For example, the sequence of characters '**' (i.e. two stars) +could be equally parsed as two '*' symbol tokens or one '**' symbol token +(see rule for 'symbol' below). +As another example, the sequence or characters '' +(i.e. carriage return followed by line feed) +could be equally parsed as two line terminators or one +(see rule for 'newline'). + +Thus, as often done in language syntax definitions, +the lexical grammar is disambiguated by +the extra-grammatical requirement that +the longest possible sequence of characters is always parsed. +This way, '**' must be parsed as one '**' symbol token, +and '' must be parsed as one line terminator. +(We should formalize this requirement, +along with the other extra-grammatical requirements given below, +and formally prove that they indeed make +the lexical grammar of Leo unambiguous.) + +As mentioned above, a character is any Unicode code point. +This grammar does not say how those are encoded in files (e.g. UTF-8): +it starts with a decoded sequence of Unicode code points. +Note that we allow any value, +even though some values may not be used according to the Unicode standard. + + +```abnf +character = %x0-10FFFF ; any Unicode code point +``` + +We give names to certain ASCII characters. + + +```abnf +horizontal-tab = %x9 +``` + + +```abnf +line-feed = %xA +``` + + +```abnf +carriage-return = %xD +``` + + +```abnf +space = %x20 +``` + + +```abnf +double-quote = %x22 +``` + +We give names to complements of certain ASCII characters. +These consist of all the Unicode characters except for one or two. + + +```abnf +not-double-quote = %x0-22 / %x24-10FFFF ; anything but " +``` + + +```abnf +not-star = %x0-29 / %x2B-10FFFF ; anything but * +``` + + +```abnf +not-line-feed-or-carriage-return = %x0-9 / %xB-C / %xE-10FFFF + ; anything but LF or CR +``` + + +```abnf +not-star-or-slash = %x0-29 / %x2B-2E / %x30-10FFFF ; anything but * or / +``` + +Lines in Leo may be terminated via +a single carriage return, +a line feed, +or a carriage return immediately followed by a line feed. +Note that the latter combination constitutes a single line terminator, +according to the extra-grammatical rule of the longest sequence. + + +```abnf +newline = line-feed / carriage-return / carriage-return line-feed +``` + +Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; + + +Line terminators form whitespace, along with spaces and horizontal tabs. + + +```abnf +whitespace = space / horizontal-tab / newline +``` + +Go to: _[horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline), [space](#user-content-space)_; + + +There are two kinds of comments in Leo, as in other languages. +One is block comments of the form '/* ... */', +and the other is end-of-line comments '// ...'. +The first kind start at '/*' and end at the first '*/', +possibly spanning multiple (partial) lines; +they do no nest. +The second kind start at '//' and extend till the end of the line. +The rules about comments given below are similar to +the ones used in the Java language specification. + + +```abnf +comment = block-comment / end-of-line-comment +``` + +Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; + + + +```abnf +block-comment = "/*" rest-of-block-comment +``` + +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment)_; + + + +```abnf +rest-of-block-comment = "*" rest-of-block-comment-after-star + / not-star rest-of-block-comment +``` + +Go to: _[not-star](#user-content-not-star), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_; + + + +```abnf +rest-of-block-comment-after-star = "/" + / "*" rest-of-block-comment-after-star + / not-star-or-slash rest-of-block-comment +``` + +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_; + + + +```abnf +end-of-line-comment = "//" *not-line-feed-or-carriage-return newline +``` + +Go to: _[newline](#user-content-newline)_; + + +Below are the keywords in the Leo language. +They cannot be used as identifiers. + + +```abnf +keyword = "address" + / "as" + / "bool" + / "circuit" + / "console" + / "const" + / "else" + / "false" + / "field" + / "for" + / "function" + / "group" + / "i8" + / "i16" + / "i32" + / "i64" + / "i128" + / "if" + / "import" + / "in" + / "input" + / "let" + / "mut" + / "return" + / "Self" + / "self" + / "static" + / "string" + / "true" + / "u8" + / "u16" + / "u32" + / "u64" + / "u128" +``` + +The following rules define (ASCII) digits +and (uppercase and lowercase) letters. + + +```abnf +digit = %x30-39 ; 0-9 +``` + + +```abnf +uppercase-letter = %x41-5A ; A-Z +``` + + +```abnf +lowercase-letter = %x61-7A ; a-z +``` + + +```abnf +letter = uppercase-letter / lowercase-letter +``` + +Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_; + + +An identifier is a non-empty sequence of letters, digits, and underscores, +starting with a letter. +It must not be a keyword: this is an extra-grammatical constraint. + + +```abnf +identifier = letter *( letter / digit / "_" ) ; but not a keyword +``` + +Go to: _[letter](#user-content-letter)_; + + +A package name consists of one or more segments separated by single dashes, +where each segment is a non-empty sequence of lowercase letters and digits. + + +```abnf +package-name = 1*( lowercase-letter / digit ) + *( "-" 1*( lowercase-letter / digit ) ) +``` + +An address starts with 'aleo1' +and continues with exactly 58 lowercase letters and digits. +Thus an address always consists of 63 characters. + + +```abnf +address = "aleo1" 58( lowercase-letter / digit ) +``` + +A format string is a sequence of characters, other than double quote, +surrounded by double quotes. +Within a format string, substrings '{}' are distinguished as containers +(these are the ones that may be matched with values +whose textual representation replaces the containers +in the printed string). +There is an implicit extra-grammatical requirements that +the explicit 'formatted-string-container' instances include +all the occurrences of '{}' in the parsed character sequence: +that is, there may not be two contiguous 'not-double-quote' instances +that are '{' and '}'. + + +```abnf +formatted-string-container = "{}" +``` + + +```abnf +formatted-string = double-quote + *( not-double-quote / formatted-string-container ) + double-quote +``` + +Go to: _[double-quote](#user-content-double-quote)_; + + +Here is (part of this ABNF comment), +an alternative way to specify format strings, +which captures the extra-grammatical requirement above in the grammar +but is more complicated: + + + +``` +not-double-quote-or-open-brace = %x0-22 / %x24-7A / %x7C-10FFFF +``` + + + +``` +not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF +``` + + + +``` +formatted-string-element = not-double-quote-or-open-brace + / "{" not-double-quote-or-close-brace + / formatted-string-container +``` + + + +``` +formatted-string = double-quote *formatted-string-element double-quote +``` + + + +It is not immediately clear which approach is better; there are tradeoffs. +Regardless, we should choose one eventually. + +Annotations are built out of names and arguments, which are tokens. +Two names are currently supported. +An argument is a sequence of one or more letters, digits, and underscores. + + +```abnf +annotation-name = "@" identifier +``` + +Go to: _[identifier](#user-content-identifier)_; + + +A natural (number) is a sequence of one or more digits. +Note that we allow leading zeros, e.g. '007'. + + +```abnf +natural = 1*digit +``` + +An integer (number) is either a natural or its negation. +Note that we also allow leading zeros in negative numbers, e.g. '-007'. + + +```abnf +integer = [ "-" ] natural +``` + +Go to: _[natural](#user-content-natural)_; + + +An untyped literal is just an integer. + + +```abnf +untyped-literal = integer +``` + +Go to: _[integer](#user-content-integer)_; + + +Unsigned literals are naturals followed by unsigned types. + + +```abnf +unsigned-literal = natural ( "u8" / "u16" / "u32" / "u64" / "u128" ) +``` + +Go to: _[natural](#user-content-natural)_; + + +Signed literals are integers followed by signed types. + + +```abnf +signed-literal = integer ( "i8" / "i16" / "i32" / "i64" / "i128" ) +``` + +Go to: _[integer](#user-content-integer)_; + + +Field literals are integers followed by the type of field elements. + + +```abnf +field-literal = integer "field" +``` + +Go to: _[integer](#user-content-integer)_; + + +There are two kinds of group literals. +One is a single integer followed by the type of group elements, +which denotes the scalar product of the generator point by the integer. +The other is a pair of integer coordinates, +which are reduced modulo the prime to identify a point, +which must be on the elliptic curve. +It is also allowed to omit one (not both) coordinates, +with an indication of how to infer the missing coordinate +(i.e. sign high, sign low, or inferred). + + +```abnf +product-group-literal = integer "group" +``` + +Go to: _[integer](#user-content-integer)_; + + + +```abnf +group-coordinate = integer / "+" / "-" / "_" +``` + +Go to: _[integer](#user-content-integer)_; + + + +```abnf +affine-group-literal = "(" group-coordinate "," group-coordinate ")" "group" +``` + +Go to: _[group-coordinate](#user-content-group-coordinate)_; + + + +```abnf +group-literal = product-group-literal / affine-group-literal +``` + +Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_; + + +Note that the rule for group literals above +allows no whitespace between coordinates. +If we want to allow whitespace, +e.g. '(3, 4)group' as opposed to requiring '(3,4)group', +then we should define affine group literals +in the syntactic grammar instead of in the lexical grammar. +We should have a notion of atomic literal in the lexical grammar, +and (non-atomic) literal in the syntactic grammar. +The lexical grammar should define a token for ')group' +if we want no whitespace between the closing parenthesis and 'group'. +More precisely, the rule for 'literal' below in the lexical grammar +would be replaced with + + + +``` +atomic-literal = ... / product-group-literal +``` + + + +where the '...' stands for all the '...-literal' alternatives +in the current rule for 'literal' below, except 'group-literal'. +Furthermore, the rule for 'symbol' below in the lexical grammar +would be extended to + + + +``` +symbol = ... / ")group" +``` + + + +where '...' stands for the current definiens of the rule. +We would also have to adjust the rule for 'token' below in the lexical grammar +to reference 'atomic-literal' instead of 'literal' in the definiens. +We would then add to the syntactic grammar the following rules + + + +``` +affine-group-literal = "(" group-coordinate "," group-coordinate ")group" +``` + + + +``` +literal = atomic-literal / affine-group-literal +``` + + + +which would now define literals in the syntactic grammar. +Note that now an affine group literal would have the form + + + +``` +( , )group +``` + + + +where is optional whitespace; +however, no whitespace is allowed between the closing ')' and 'group'. + +Boolean literals are the usual two. + + +```abnf +boolean-literal = "true" / "false" +``` + +An address literal is an address wrapped into an indication of address, +to differentiate it from an identifier. + + +```abnf +address-literal = "address" "(" address ")" +``` + +Go to: _[address](#user-content-address)_; + + +The ones above are all the literals, as defined by the following rule. + + +```abnf +literal = untyped-literal + / unsigned-literal + / signed-literal + / field-literal + / group-literal + / boolean-literal + / address-literal +``` + +Go to: _[unsigned-literal](#user-content-unsigned-literal), [untyped-literal](#user-content-untyped-literal), [field-literal](#user-content-field-literal), [group-literal](#user-content-group-literal), [address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [signed-literal](#user-content-signed-literal)_; + + +After defining the (mostly) alphanumeric tokens above, +it remains to define tokens for non-alphanumeric symbols such as "+" and "(". +Different programming languages used different terminologies for these, +e.g. operators, separators, punctuators, etc. +Here we use 'symbol', for all of them, but we can do something different. +We could give names to all of these symbols, +via rules such as + + + +``` +equality-operator = "==" +``` + + + +and defining 'symbol' in terms of those + + + +``` +symbol = ... / equality-operator / ... +``` + + + +This may or may not make the grammar more readable, +but it would help establish a terminology in the grammar, +namely the exact names of some of these token. +On the other hand, at least some of them are perhaps simple enough +that they could be just described in terms of their symbols, +e.g. 'double dot', 'question mark', etc. + + +```abnf +symbol = "!" / "&&" / "||" + / "==" / "!=" + / "<" / "<=" / ">" / ">=" + / "+" / "-" / "*" / "/" / "**" + / "=" / "+=" / "-=" / "*=" / "/=" / "**=" + / "(" / ")" + / "[" / "]" + / "{" / "}" + / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" + / "->" / "_" +``` + +Everything defined above, other than comments and whitespace, +is a token, as defined by the following rule. + + +```abnf +token = keyword + / identifier + / literal + / package-name + / formatted-string + / annotation-name + / symbol +``` + +Go to: _[literal](#user-content-literal), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string), [symbol](#user-content-symbol), [identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name)_; + + + +-------- + + +Syntactic Grammar +----------------- + +The processing defined by the lexical grammar above +turns the initial sequence of characters +into a sequence of tokens, comments, and whitespaces. +The purpose of comments and whitespaces, from a syntactic point of view, +is just to separate tokens: +they are discarded, leaving a sequence of tokens. +The syntactic grammar describes how to turn +a sequence of tokens into concrete syntax trees. + +There are unsigned and signed integer types, for five sizes. + + +```abnf +unsigned-type = "u8" / "u16" / "u32" / "u64" / "u128" +``` + + +```abnf +signed-type = "i8" / "i16" / "i32" / "i64" / "i128" +``` + + +```abnf +integer-type = unsigned-type / signed-type +``` + +Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; + + +The integer types, along with the field and group types, +for the arithmetic types, i.e. the ones that support arithmetic operations. + + +```abnf +field-type = "field" +``` + + +```abnf +group-type = "group" +``` + + +```abnf +arithmetic-type = integer-type / field-type / group-type +``` + +Go to: _[field-type](#user-content-field-type), [group-type](#user-content-group-type), [integer-type](#user-content-integer-type)_; + + +The arithmetic types, along with the boolean and address types, +form the scalar types, i.e. the ones whose values do not contain (sub)values. + + +```abnf +boolean-type = "bool" +``` + + +```abnf +address-type = "address" +``` + + +```abnf +scalar-type = boolean-type / arithmetic-type / address-type +``` + +Go to: _[arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type)_; + + +Circuit types are denoted by identifiers and the keyword 'Self'. +The latter is only allowed inside a circuit definition, +to denote the defined circuit. + + +```abnf +self-type = "Self" +``` + + +```abnf +circuit-type = identifier / self-type +``` + +Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; + + +A tuple type consists of zero, two, or more component types. + + +```abnf +tuple-type = "(" [ type 1*( "," type ) ] ")" +``` + +Go to: _[type](#user-content-type)_; + + +An array type consists of an element type +and an indication of dimensions. +There is either a single dimension (a number), +or a tuple of one or more dimensions +(we could restrict the latter to two or more dimensions). + + +```abnf +array-type = "[" type ";" array-dimensions "]" +``` + +Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_; + + + +```abnf +array-dimensions = natural + / "(" natural *( "," natural ) ")" +``` + +Go to: _[natural](#user-content-natural)_; + + +Circuit, tuple, and array types form the aggregate types, +i.e. types whose values contain (sub)values +(with the corner-case exception of the empty tuple value). + + +```abnf +aggregate-type = tuple-type / array-type / circuit-type +``` + +Go to: _[array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type)_; + + +Scalar and aggregate types form all the types. + + +```abnf +type = scalar-type / aggregate-type +``` + +Go to: _[scalar-type](#user-content-scalar-type), [aggregate-type](#user-content-aggregate-type)_; + + +As often done in grammatical language syntax specifications, +we define rules for different kinds of expressions, +which also defines the relative precedence +of operators and other expression constructs, +and the (left or right) associativity of binary operators. + +The primary expressions are self-contained in a way, +i.e. they have clear deliminations. +Some consist of single tokens: +identifiers, the keywords 'self' and 'input', and literals. +Primary expressions also include parenthesized expressions, +i.e. any expression may be turned into a primary one +by putting parentheses around it. +The other kinds are defined and explained below. + + +```abnf +primary-expression = identifier + / "self" + / "input" + / literal + / "(" expression ")" + / tuple-expression + / array-expression + / circuit-expression + / function-call +``` + +Go to: _[function-call](#user-content-function-call), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [tuple-expression](#user-content-tuple-expression)_; + + +There are tuple expressions to construct and deconstruct tuples. +A construction consists of zero, two, or more component expressions. +A deconstruction uses a component index (zero-indexed). +Note that constructions are delimited by closing parentheses +and deconstructions are delimited by natural tokens. +The rule below, and similar rules for other aggregate types, +use the perhaps more familiar 'access', +but note that 'deconstruction' has a nice symmetry to 'construction'; +the term 'destructor' has a different meaning in other languages, +so we may want to avoid it, but not necessarily. + + +```abnf +tuple-construction = "(" [ expression 1*( "," expression ) ] ")" +``` + +Go to: _[expression](#user-content-expression)_; + + + +```abnf +tuple-expression = tuple-construction +``` + +Go to: _[tuple-construction](#user-content-tuple-construction)_; + + +The are array expressions to construct and deconstruct arrays. +There are two kinds of constructions: +one lists the element expressions (at least one), +including spreads (via '...') which are arrays being spliced in; +the other repeats (the value of) a single expression +across one or more dimensions. +There are two kinds of deconstructions: +one selects a single element by index (zero-indexed); +the other selects a range via two indices, +the first inclusive and the second exclusive -- +both are optional, +the first defaulting to 0 and the second to the array length. +Note that these expressions are all delimited +by closing square brackets. + + +```abnf +array-inline-construction = "[" + array-inline-element + *( "," array-inline-element ) + "]" +``` + +Go to: _[array-inline-element](#user-content-array-inline-element)_; + + + +```abnf +array-inline-element = expression / "..." expression +``` + +Go to: _[expression](#user-content-expression)_; + + + +```abnf +array-repeat-construction = "[" expression ";" array-dimensions "]" +``` + +Go to: _[expression](#user-content-expression), [array-dimensions](#user-content-array-dimensions)_; + + + +```abnf +array-construction = array-inline-construction / array-repeat-construction +``` + +Go to: _[array-inline-construction](#user-content-array-inline-construction), [array-repeat-construction](#user-content-array-repeat-construction)_; + + + +```abnf +array-expression = array-construction +``` + +Go to: _[array-construction](#user-content-array-construction)_; + + +There are circuit expressions to construct and deconstruct circuit values. +A construction lists values for all the member variables (in any order); +there must be at least one member variable currently. +A single identifier abbreviates +a pair consisting of the same identifier separated by dot; +note that, in the expansion, the left one denotes a member name, +while the right one denotes an expression (a variable), +so they are syntactically identical but semantically different. +A deconstruction selects a member variable by name. +Note that these expressions are delimited, +by closing curly braces or identifiers. + + +```abnf +circuit-construction = circuit-type "{" + circuit-inline-element *( "," circuit-inline-element ) + "}" +``` + +Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; + + + +```abnf +circuit-inline-element = identifier ":" expression / identifier +``` + +Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression)_; + + + +```abnf +circuit-expression = circuit-construction +``` + +Go to: _[circuit-construction](#user-content-circuit-construction)_; + + +There are three kinds of function calls: +top-level function calls, +instance (i.e. non-static) member function calls, and +static member function calls. +What changes is the start, but they all end in an argument list, +delimited by a closing parenthesis. + + +```abnf +function-arguments = "(" [ expression *( "," expression ) ] ")" +``` + +Go to: _[expression](#user-content-expression)_; + + +Postfix expressions have highest precedence. +They apply to primary expressions. +Contains access expressions for arrays, tuples, and circuits. +Contains function call types. +postfix-expression = primary-expression + / postfix-expression "." natural + / postfix-expression "." identifier + / identifier function-arguments + / postfix-expression "." identifier function-arguments + / circuit-type "::" identifier function-arguments + / postfix-expression "[" expression "]" + / postfix-expression "[" [expression] ".." [expression] "]" + +Unary operators have the highest operator precedence. +They apply to postfix expressions +and recursively to unary expressions. + + +```abnf +unary-expression = postfix-expression + / "!" unary-expression + / "-" unary-expression +``` + +Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_; + + +Next in the operator precedence is casting. +The current rule below makes exponentiation left-associative, +cast-expression = unary-expression + / cast-expression "as" type + +Next in the operator precedence is exponentiation, +following mathematical practice. +The current rule below makes exponentiation left-associative, +i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. +This is easy to change if we want it to be right-associative instead. + + +```abnf +exponential-expression = cast-expression + / exponential-expression "**" cast-expression +``` + +Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_; + + +Next in precedence come multiplication and division, both left-associative. + + +```abnf +multiplicative-expression = exponential-expression + / multiplicative-expression "*" exponential-expression + / multiplicative-expression "/" exponential-expression +``` + +Go to: _[exponential-expression](#user-content-exponential-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; + + +Then there are addition and subtraction, both left-assocative. + + +```abnf +additive-expression = multiplicative-expression + / additive-expression "+" multiplicative-expression + / additive-expression "-" multiplicative-expression +``` + +Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; + + +Next in the precedence order are ordering relations. +These are not associative, because they return boolean values. + + +```abnf +ordering-expression = additive-expression + / additive-expression "<" additive-expression + / additive-expression ">" additive-expression + / additive-expression "<=" additive-expression + / additive-expression ">=" additive-expression +``` + +Go to: _[additive-expression](#user-content-additive-expression)_; + + +Equalities return booleans but may also operate on boolean, +so we make them left-associative. + + +```abnf +equality-expression = ordering-expression + / equality-expression "==" ordering-expression + / equality-expression "!=" ordering-expression +``` + +Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; + + +Next come conjunctive expressions, left-associative. + + +```abnf +conjunctive-expression = equality-expression + / conjunctive-expression "&&" equality-expression +``` + +Go to: _[equality-expression](#user-content-equality-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; + + +Next come disjunctive expressions, left-associative. + + +```abnf +disjunctive-expression = conjunctive-expression + / disjunctive-expression "||" conjunctive-expression +``` + +Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; + + +Finally we have conditional expressions. + + +```abnf +conditional-expression = disjunctive-expression + / conditional-expression + "?" expression + ":" conditional-expression +``` + +Go to: _[conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; + + +These are all the expressions. +Recall that conditional expressions +may be disjunctive expressions, +which may be conjunctive expressions, +and so on all the way to primary expressions. + + +```abnf +expression = conditional-expression +``` + +Go to: _[conditional-expression](#user-content-conditional-expression)_; + + +There are various kinds of statements, +including blocks, which are +possibly empty sequences of statements surounded by curly braces. + + +```abnf +statement = expression-statement + / return-statement + / variable-definition-statement + / conditional-statement + / loop-statement + / assignment-statement + / console-statement + / block +``` + +Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement), [conditional-statement](#user-content-conditional-statement), [return-statement](#user-content-return-statement), [expression-statement](#user-content-expression-statement)_; + + + +```abnf +block = "{" *statement "}" +``` + +An expression (that returns the empty tuple) +can be turned into a statement by appending a semicolon. + + +```abnf +expression-statement = expression ";" +``` + +Go to: _[expression](#user-content-expression)_; + + +A return statement always takes an expression, +and does not end with a semicolon (but we may want to change that). + + +```abnf +return-statement = "return" expression +``` + +Go to: _[expression](#user-content-expression)_; + + +There are two kinds of variable definition statements, +which only differ in the starting keyword. +The variables are either a single one or a tuple of two or more; +in all cases, there is just one optional type +and just one initializing expression. + + +```abnf +variable-definition-statement = ( "let" / "const" ) + identifier-or-identifiers + [ ":" type ] "=" expression ";" +``` + +Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type), [expression](#user-content-expression)_; + + + +```abnf +identifier-or-identifiers = identifier + / "(" identifier 1*( "," identifier ) ")" +``` + +Go to: _[identifier](#user-content-identifier)_; + + +A conditional statement always starts with a condition and a block +(which together form a branch). +It may stop there, or it may continue with an alternative block, +or possibly with another conditional statement, forming a chain. +Note that we require blocks in all branches, not merely statements. + + +```abnf +branch = "if" expression block +``` + +Go to: _[block](#user-content-block), [expression](#user-content-expression)_; + + + +```abnf +conditional-statement = branch + / branch "else" block + / branch "else" conditional-statement +``` + +Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_; + + +A loop statement implicitly defines a loop variable +that goes from a starting value (inclusive) to an ending value (exclusive). +The body is a block. + + +```abnf +loop-statement = "for" identifier "in" expression ".." expression block +``` + +Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_; + + +An assignment statement is straightforward. +Based on the operator, the assignment may be simple (i.e. '=') +or compound (i.e. combining assignment with an arithmetic operation). + + +```abnf +assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" +``` + + +```abnf +assignment-statement = expression assignment-operator expression ";" +``` + +Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_; + + +Console statements start with the 'console' keyword, +followed by a console function call. +The call may be an assertion or a print command. +The former takes an expression (which must be boolean) as argument. +The latter takes either no argument, +or a format string followed by expressions, +whose number must match the number of containers '{}' in the format string. +Note that the console function names are identifiers, not keywords. +There are three kind of printing. + + +```abnf +console-statement = "console" "." console-call +``` + +Go to: _[console-call](#user-content-console-call)_; + + + +```abnf +console-call = assert-call + / print-call +``` + +Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_; + + + +```abnf +assert-call = "assert" "(" expression ")" +``` + +Go to: _[expression](#user-content-expression)_; + + + +```abnf +print-function = "debug" / "error" / "log" +``` + + +```abnf +print-arguments = "(" [ formatted-string *( "," expression ) ] ")" +``` + +Go to: _[formatted-string](#user-content-formatted-string)_; + + + +```abnf +print-call = print-function print-arguments +``` + +Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; + + +An annotation consists of an annotation name (which starts with '@') +with optional annotation arguments. +Note that no parentheses are used if there are no arguments. + + +```abnf +annotation = annotation-name + [ "(" identifier *( "," identifier ) ")" ] +``` + +Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_; + + +A function declaration defines a function. +This could be called 'function-definition' instead, +but see the comments about the 'declaration' rule below. +The output type is optional (it defaults to the empty tuple type). +In general, a function input consists of an identifier and a type, +with an optional 'const' modifier. +However, functions inside circuits +may start with a 'mut self' or 'self' parameter, +which may be the only parameter in fact. +Furthermore, any function may end with an 'input' parameter, +which may be the only parameter in fact. + + +```abnf +function-declaration = *annotation "function" identifier + "(" [ function-parameters ] ")" [ "->" type ] + block +``` + +Go to: _[function-parameters](#user-content-function-parameters), [type](#user-content-type), [block](#user-content-block), [identifier](#user-content-identifier)_; + + + +```abnf +function-parameters = self-parameter [ "," input-parameter ] + / self-parameter "," function-inputs [ "," input-parameter ] + / function-inputs [ "," input-parameter ] + / input-parameter +``` + +Go to: _[input-parameter](#user-content-input-parameter), [function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter)_; + + + +```abnf +self-parameter = ["mut"] "self" +``` + + +```abnf +function-inputs = function-input *( "," function-input ) +``` + +Go to: _[function-input](#user-content-function-input)_; + + + +```abnf +function-input = [ "const" ] identifier ":" type +``` + +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; + + + +```abnf +input-parameter = "input" +``` + +A circuit member variable declaration consists of an identifier and a type. +A circuit member function declaration consists of a function declaration. +We could call these 'member-definition' etc., +but see the comments about the 'declaration' rule below. + + +```abnf +member-declaration = member-variable-declaration + / member-function-declaration +``` + +Go to: _[member-variable-declaration](#user-content-member-variable-declaration), [member-function-declaration](#user-content-member-function-declaration)_; + + + +```abnf +member-variable-declaration = identifier ":" type +``` + +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; + + + +```abnf +member-function-declaration = function-declaration +``` + +Go to: _[function-declaration](#user-content-function-declaration)_; + + +A circuit declaration defines a circuit type. It is straightforward. +This could be called 'circuit-definition' instead, +but see the comments about the 'declaration' rule below. + + +```abnf +circuit-declaration = *annotation "circuit" identifier + "{" member-declaration *( "," member-declaration ) "}" +``` + +Go to: _[member-declaration](#user-content-member-declaration), [identifier](#user-content-identifier)_; + + +An import declaration consists of the 'import' keyword +followed by a package path, which may be one of the following: +a single wildcard; +an identifier, optionally followed by a local renamer; +a package name followed by a path, recursively; +or a parenthesized list of package paths, +which are "fan out" of the initial path. +Note that we allow the last element of the parenthesized list +to be followed by a comma, presumably for convenience. + + +```abnf +import-declaration = "import" package-path +``` + +Go to: _[package-path](#user-content-package-path)_; + + + +```abnf +package-path = "*" + / identifier [ "as" identifier ] + / package-name "." package-path + / "(" package-path *( "," package-path ) [","] ")" +``` + +Go to: _[identifier](#user-content-identifier), [package-name](#user-content-package-name), [package-path](#user-content-package-path)_; + + +Finally, we define a file as a sequence of zero or more declarations. +This is why we used 'function-declaration' and 'circuit-declaration' +instead of 'function-definition' and 'ciruit-definition': +this way, they are all declarations of some sort. +An import declaration cannot really called an import definition, +because it does not define anything. +But we may revisit this, and use 'definition' instead of 'declaration'. + + +```abnf +declaration = import-declaration + / function-declaration + / circuit-declaration +``` + +Go to: _[import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_; + + + +```abnf +file = *declaration + diff --git a/grammar/src/main.rs b/grammar/src/main.rs index 6c70568ded..22465b66d2 100644 --- a/grammar/src/main.rs +++ b/grammar/src/main.rs @@ -76,7 +76,7 @@ impl<'a> Processor<'a> { /// Main function for this struct. /// Goes through each line and transforms it into proper markdown. - fn process(&mut self) -> Result<()> { + fn process(&mut self) { let lines = self.grammar.lines(); let mut prev = ""; @@ -85,27 +85,27 @@ impl<'a> Processor<'a> { // code block in comment (not highlighted as abnf) if let Some(code) = line.strip_prefix("; ") { - self.enter_scope(Scope::Code)?; + self.enter_scope(Scope::Code); self.append_str(code); // just comment. end of code block } else if let Some(code) = line.strip_prefix("; ") { - self.enter_scope(Scope::Free)?; + self.enter_scope(Scope::Free); self.append_str(code); // horizontal rule - section separator } else if line.starts_with(";;;;;;;;;;") { - self.enter_scope(Scope::Free)?; + self.enter_scope(Scope::Free); self.append_str("\n--------\n"); // empty line in comment. end of code block } else if line.starts_with(';') { - self.enter_scope(Scope::Free)?; + self.enter_scope(Scope::Free); self.append_str("\n\n"); // just empty line. end of doc, start of definition } else if line.is_empty() { - self.enter_scope(Scope::Free)?; + self.enter_scope(Scope::Free); self.append_str(""); // definition (may be multiline) @@ -118,7 +118,7 @@ impl<'a> Processor<'a> { // try to find rule matching definition or fail let rule = self.rules.get(&def.to_string()).cloned().unwrap(); - self.enter_scope(Scope::Definition(rule))?; + self.enter_scope(Scope::Definition(rule)); } self.append_str(line); @@ -126,8 +126,6 @@ impl<'a> Processor<'a> { prev = line; } - - Ok(()) } /// Append new line into output, add newline character. @@ -138,7 +136,7 @@ impl<'a> Processor<'a> { /// Enter new scope (definition or code block). Allows customizing /// pre and post lines for each scope entered or exited. - fn enter_scope(&mut self, new_scope: Scope) -> Result<()> { + fn enter_scope(&mut self, new_scope: Scope) { match (&self.scope, &new_scope) { // exchange scopes between Free and Code (Scope::Free, Scope::Code) => self.append_str("```"), @@ -174,8 +172,6 @@ impl<'a> Processor<'a> { }; self.scope = new_scope; - - Ok(()) } } @@ -215,7 +211,7 @@ fn main() -> Result<()> { // Init parser and run it. That's it. let mut parser = Processor::new(grammar, parsed); - parser.process()?; + parser.process(); // Print result of conversion to STDOUT. println!("{}", parser.out); From a1d48d425187b8dfdfde0c3fba93a36b72168aca Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 31 Mar 2021 20:54:16 +0300 Subject: [PATCH 054/108] makes --path global --- leo/main.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/leo/main.rs b/leo/main.rs index 226dbd89fb..9d6c7f775e 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -55,7 +55,12 @@ struct Opt { #[structopt(subcommand)] command: CommandOpts, - #[structopt(short, long, help = "Optional path to Leo program root folder", parse(from_os_str))] + #[structopt( + long, + global = true, + help = "Optional path to Leo program root folder", + parse(from_os_str) + )] path: Option, } From cd6ec7eba98d98a990d5afb918c8bb439edce4ea Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 31 Mar 2021 18:24:44 +0000 Subject: [PATCH 055/108] Bump anyhow from 1.0.39 to 1.0.40 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.39 to 1.0.40. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.39...1.0.40) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 96cf654c71..d21daf157d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arrayref" From dc8a04e872f851addbdfa97202fba8793462bae7 Mon Sep 17 00:00:00 2001 From: gluax Date: Wed, 31 Mar 2021 14:59:45 -0400 Subject: [PATCH 056/108] fix test --- .../canonicalization/compound_assignment.json | 36 +++++++++---------- .../canonicalization/compound_assignment.leo | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/compiler/tests/canonicalization/compound_assignment.json b/compiler/tests/canonicalization/compound_assignment.json index 39c4ffa7da..fa2c4825a5 100644 --- a/compiler/tests/canonicalization/compound_assignment.json +++ b/compiler/tests/canonicalization/compound_assignment.json @@ -715,10 +715,10 @@ "Assign": { "operation": "Assign", "assignee": { - "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":3,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f = foo.f + 2u8;\\\"}\"}", + "identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":3,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}", "accesses": [ { - "Member": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f = foo.f + 2u8;\\\"}\"}" + "Member": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}" } ], "span": { @@ -727,7 +727,7 @@ "col_start": 3, "col_stop": 8, "path": "", - "content": " foo.f = foo.f + 2u8;" + "content": " foo.f += 2u8;" } }, "value": { @@ -735,16 +735,16 @@ "left": { "CircuitMemberAccess": { "circuit": { - "Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":11,\\\"col_stop\\\":14,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f = foo.f + 2u8;\\\"}\"}" + "Identifier": "{\"name\":\"foo\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":3,\\\"col_stop\\\":6,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}" }, - "name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":15,\\\"col_stop\\\":16,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f = foo.f + 2u8;\\\"}\"}", + "name": "{\"name\":\"f\",\"span\":\"{\\\"line_start\\\":18,\\\"line_stop\\\":18,\\\"col_start\\\":7,\\\"col_stop\\\":8,\\\"path\\\":\\\"\\\",\\\"content\\\":\\\" foo.f += 2u8;\\\"}\"}", "span": { "line_start": 18, "line_stop": 18, - "col_start": 11, - "col_stop": 16, + "col_start": 3, + "col_stop": 15, "path": "", - "content": " foo.f = foo.f + 2u8;" + "content": " foo.f += 2u8;" } } }, @@ -756,10 +756,10 @@ { "line_start": 18, "line_stop": 18, - "col_start": 19, - "col_stop": 22, + "col_start": 12, + "col_stop": 15, "path": "", - "content": " foo.f = foo.f + 2u8;" + "content": " foo.f += 2u8;" } ] } @@ -768,10 +768,10 @@ "span": { "line_start": 18, "line_stop": 18, - "col_start": 11, - "col_stop": 22, + "col_start": 3, + "col_stop": 15, "path": "", - "content": " foo.f = foo.f + 2u8;" + "content": " foo.f += 2u8;" } } }, @@ -779,9 +779,9 @@ "line_start": 18, "line_stop": 18, "col_start": 3, - "col_stop": 22, + "col_stop": 15, "path": "", - "content": " foo.f = foo.f + 2u8;" + "content": " foo.f += 2u8;" } } }, @@ -851,7 +851,7 @@ "col_start": 17, "col_stop": 2, "path": "", - "content": "function main() {\n...\n}" + "content": "function main() {\n...\n} " } }, "span": { @@ -860,7 +860,7 @@ "col_start": 1, "col_stop": 2, "path": "", - "content": "function main() {\n...\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + "content": "function main() {\n...\n} \n\n\n\n\n\n\n\n\n\n\n\n\n\n" } } } diff --git a/compiler/tests/canonicalization/compound_assignment.leo b/compiler/tests/canonicalization/compound_assignment.leo index c7a633c9a4..346d4de3c7 100644 --- a/compiler/tests/canonicalization/compound_assignment.leo +++ b/compiler/tests/canonicalization/compound_assignment.leo @@ -15,6 +15,6 @@ function main() { console.assert(z.1 == 5u8); let foo = Foo { f: 6u8 }; - foo.f = foo.f + 2u8; + foo.f += 2u8; console.assert(foo.f == 8u8); } \ No newline at end of file From 2aabb09468b82aef2d3450ea94444e4430e7bf47 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 31 Mar 2021 22:14:03 -0700 Subject: [PATCH 057/108] Adds a noconfig feature for release builds --- .cargo/config | 2 +- .github/workflows/release.yml | 6 +++--- Cargo.toml | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.cargo/config b/.cargo/config index 7c6d594717..932cf0b635 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,2 @@ -[target.'cfg(not(target_arch = "wasm32"))'] +[target.'cfg(any(not(target_arch = "wasm32"), feature = "release"))'] rustflags = ["-C", "target-cpu=native"] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f65b75fc4f..0dfacf2351 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: - name: Build Leo run: | - cargo build --all --release && strip target/release/leo + cargo build --all --release --features noconfig && strip target/release/leo env: CARGO_NET_GIT_FETCH_WITH_CLI: true @@ -67,7 +67,7 @@ jobs: - name: Build Leo run: | - cargo build --all --release && strip target/release/leo + cargo build --all --release --features noconfig && strip target/release/leo env: CARGO_NET_GIT_FETCH_WITH_CLI: true @@ -118,7 +118,7 @@ jobs: - name: Build Leo run: | - cargo build --all --release + cargo build --all --release --features noconfig env: CARGO_NET_GIT_FETCH_WITH_CLI: true diff --git a/Cargo.toml b/Cargo.toml index 38dc4f2418..46f2e3d7cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,8 +155,10 @@ version = "0.5" version = "0.11.2" [features] -default = [ ] +default = [] ci_skip = [ "leo-compiler/ci_skip" ] +# This feature flag is used to disable `target-cpu=native` in `.cargo/config`. +noconfig = [] [profile.release] opt-level = 3 From 54192f25895bff9fe32e043e25d8aa0c2a40d237 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 31 Mar 2021 23:14:01 -0700 Subject: [PATCH 058/108] Update CI to 1.51 --- .circleci/config.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b8dd6eeddb..6099e4ae35 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -44,7 +44,7 @@ jobs: rust-stable: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - checkout @@ -62,7 +62,7 @@ jobs: rust-nightly: docker: - - image: howardwu/snarkos-ci:2021-01-31 + - image: howardwu/snarkos-ci:2021-03-25 resource_class: xlarge steps: - checkout @@ -77,8 +77,8 @@ jobs: leo-executable: docker: - - image: cimg/rust:1.50.0 - resource_class: xlarge + - image: cimg/rust:1.51.0 + resource_class: 2xlarge steps: - checkout - setup_environment: @@ -95,7 +95,7 @@ jobs: leo-new: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -108,7 +108,7 @@ jobs: leo-init: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -121,7 +121,7 @@ jobs: leo-clean: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -134,7 +134,7 @@ jobs: leo-setup: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -147,7 +147,7 @@ jobs: leo-add-remove: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -160,7 +160,7 @@ jobs: leo-login-logout: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -173,7 +173,7 @@ jobs: leo-clone: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: @@ -186,7 +186,7 @@ jobs: leo-publish: docker: - - image: cimg/rust:1.50.0 + - image: cimg/rust:1.51.0 resource_class: xlarge steps: - attach_workspace: From 2a2b9994d0bc7de410efa9df9beb66957ac44402 Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 31 Mar 2021 23:20:10 -0700 Subject: [PATCH 059/108] Lock the cargo file --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6099e4ae35..4dc51b709b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -78,7 +78,7 @@ jobs: leo-executable: docker: - image: cimg/rust:1.51.0 - resource_class: 2xlarge + resource_class: xlarge steps: - checkout - setup_environment: @@ -86,7 +86,7 @@ jobs: - run: name: Build and install Leo no_output_timeout: 30m - command: cargo install --path . --root . + command: cargo install --path . --root . --locked - persist_to_workspace: root: ~/ paths: project/ From f76793572c4179924a08821c46adc9d217f19641 Mon Sep 17 00:00:00 2001 From: damirka Date: Thu, 1 Apr 2021 23:10:34 +0300 Subject: [PATCH 060/108] added --path to leo init ci --- .circleci/leo-add-remove.sh | 2 +- .circleci/leo-init.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/leo-add-remove.sh b/.circleci/leo-add-remove.sh index e7eb352934..de855a4ed8 100755 --- a/.circleci/leo-add-remove.sh +++ b/.circleci/leo-add-remove.sh @@ -1,6 +1,6 @@ # leo add (w/o login) & remove -$LEO new my-app && cd my-app +$LEO new my-app && cd my-app || exit 1 $LEO add howard/silly-sudoku $LEO remove silly-sudoku $LEO clean diff --git a/.circleci/leo-init.sh b/.circleci/leo-init.sh index ab7724cd4a..47d6966001 100755 --- a/.circleci/leo-init.sh +++ b/.circleci/leo-init.sh @@ -1,4 +1,4 @@ -mkdir hello-world && cd hello-world || exit 1 -$LEO init -ls -la -$LEO run +mkdir hello-world +$LEO init --path hello-world || exit 1 +ls -la hello-world +$LEO run --path hello-world From 6b3aa7a7d061defdd22cf11be12277cc2d86fddb Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Thu, 1 Apr 2021 14:27:25 -0700 Subject: [PATCH 061/108] Update config --- .cargo/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cargo/config b/.cargo/config index 932cf0b635..4ba3c3347a 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,2 @@ -[target.'cfg(any(not(target_arch = "wasm32"), feature = "release"))'] +[target.'cfg(any(not(target_arch = "wasm32"), feature = "noconfig"))'] rustflags = ["-C", "target-cpu=native"] From 952ce8c17e115ce127c09699a5e5ac1288124f87 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 2 Apr 2021 04:45:02 -0400 Subject: [PATCH 062/108] allow mutable method from immutable context --- asg/src/expression/circuit_init.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asg/src/expression/circuit_init.rs b/asg/src/expression/circuit_init.rs index a36fa5a43c..3eced2d008 100644 --- a/asg/src/expression/circuit_init.rs +++ b/asg/src/expression/circuit_init.rs @@ -67,7 +67,7 @@ impl<'a> ExpressionNode<'a> for CircuitInitExpression<'a> { } fn is_mut_ref(&self) -> bool { - false + true } fn const_value(&self) -> Option { From f44dcc1e96b08628002b53c91d574e7cd8f7dac0 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 2 Apr 2021 04:50:14 -0400 Subject: [PATCH 063/108] test for bug --- compiler/tests/circuits/mod.rs | 8 ++++++++ .../circuits/mutable_call_immutable_context.leo | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 compiler/tests/circuits/mutable_call_immutable_context.leo diff --git a/compiler/tests/circuits/mod.rs b/compiler/tests/circuits/mod.rs index 9395853529..093e2263e1 100644 --- a/compiler/tests/circuits/mod.rs +++ b/compiler/tests/circuits/mod.rs @@ -308,3 +308,11 @@ fn test_duplicate_name_context() { assert_satisfied(program); } + +#[test] +fn test_mutable_call_immutable_context() { + let program_string = include_str!("mutable_call_immutable_context.leo"); + let program = parse_program(program_string).unwrap(); + + assert_satisfied(program); +} diff --git a/compiler/tests/circuits/mutable_call_immutable_context.leo b/compiler/tests/circuits/mutable_call_immutable_context.leo new file mode 100644 index 0000000000..d68e1866c5 --- /dev/null +++ b/compiler/tests/circuits/mutable_call_immutable_context.leo @@ -0,0 +1,12 @@ +circuit TestMe { + x: u8, + + function test_me(mut self) -> u8 { + self.x += 1; + return self.x + } +} + +function main () { + const t = TestMe {x: 6u8}.test_me(); +} \ No newline at end of file From dbf069d21521d2f206d2993ea77d644addd46066 Mon Sep 17 00:00:00 2001 From: gluax Date: Fri, 2 Apr 2021 06:20:08 -0400 Subject: [PATCH 064/108] no whitepsace between types and integers/group coords --- parser/src/parser/context.rs | 37 ++++++++++++++++++++++++--------- parser/src/parser/expression.rs | 31 +++++++++++++++++---------- parser/src/parser/file.rs | 7 +------ parser/src/parser/mod.rs | 11 ++++++++++ 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/parser/src/parser/context.rs b/parser/src/parser/context.rs index 91014c4f87..4ba080dab4 100644 --- a/parser/src/parser/context.rs +++ b/parser/src/parser/context.rs @@ -16,7 +16,7 @@ use std::unimplemented; -use crate::{tokenizer::*, SyntaxError, SyntaxResult, Token, KEYWORD_TOKENS}; +use crate::{tokenizer::*, unexpected_whitespace, SyntaxError, SyntaxResult, Token, KEYWORD_TOKENS}; use leo_ast::*; use tendril::format_tendril; @@ -164,10 +164,16 @@ impl ParserContext { /// Removes the next two tokens if they are a pair of [`GroupCoordinate`] and returns them, /// or [None] if the next token is not a [`GroupCoordinate`]. /// - pub fn eat_group_partial(&mut self) -> Option<(GroupCoordinate, GroupCoordinate, Span)> { + pub fn eat_group_partial(&mut self) -> SyntaxResult> { let mut i = self.tokens.len() - 1; - let start_span = self.tokens.get(i)?.span.clone(); - let first = self.peek_group_coordinate(&mut i)?; + let start_span = match self.tokens.get(i) { + Some(span) => span.span.clone(), + None => return Ok(None), + }; + let first = match self.peek_group_coordinate(&mut i) { + Some(coord) => coord, + None => return Ok(None), + }; match self.tokens.get(i) { Some(SpannedToken { token: Token::Comma, .. @@ -175,19 +181,24 @@ impl ParserContext { i -= 1; } _ => { - return None; + return Ok(None); } } - let second = self.peek_group_coordinate(&mut i)?; + let second = match self.peek_group_coordinate(&mut i) { + Some(coord) => coord, + None => return Ok(None), + }; + let right_paren_span; match self.tokens.get(i) { Some(SpannedToken { token: Token::RightParen, - .. + span, }) => { + right_paren_span = span.clone(); i -= 1; } _ => { - return None; + return Ok(None); } } let end_span; @@ -200,12 +211,18 @@ impl ParserContext { i -= 1; } _ => { - return None; + return Ok(None); } } self.tokens.drain((i + 1)..); - Some((first, second, start_span + end_span)) + unexpected_whitespace( + &right_paren_span, + &end_span, + &format!("({},{})", first, second), + "group", + )?; + Ok(Some((first, second, start_span + end_span))) } /// diff --git a/parser/src/parser/expression.rs b/parser/src/parser/expression.rs index 3b5d88fc0b..042a0520b5 100644 --- a/parser/src/parser/expression.rs +++ b/parser/src/parser/expression.rs @@ -554,7 +554,7 @@ impl ParserContext { /// tuple initialization expression. /// pub fn parse_tuple_expression(&mut self, span: &Span) -> SyntaxResult { - if let Some((left, right, span)) = self.eat_group_partial() { + if let Some((left, right, span)) = self.eat_group_partial()? { return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple( GroupTuple { span, @@ -657,19 +657,28 @@ impl ParserContext { Some(SpannedToken { token: Token::Field, span: type_span, - }) => Expression::Value(ValueExpression::Field(value, span + type_span)), + }) => { + unexpected_whitespace(&span, &type_span, &value, "field")?; + Expression::Value(ValueExpression::Field(value, span + type_span)) + } Some(SpannedToken { token: Token::Group, span: type_span, - }) => Expression::Value(ValueExpression::Group(Box::new(GroupValue::Single( - value, - span + type_span, - )))), - Some(SpannedToken { token, span: type_span }) => Expression::Value(ValueExpression::Integer( - Self::token_to_int_type(token).expect("unknown int type token"), - value, - span + type_span, - )), + }) => { + unexpected_whitespace(&span, &type_span, &value, "group")?; + Expression::Value(ValueExpression::Group(Box::new(GroupValue::Single( + value, + span + type_span, + )))) + } + Some(SpannedToken { token, span: type_span }) => { + unexpected_whitespace(&span, &type_span, &value, &token.to_string())?; + Expression::Value(ValueExpression::Integer( + Self::token_to_int_type(token).expect("unknown int type token"), + value, + span + type_span, + )) + } None => Expression::Value(ValueExpression::Implicit(value, span)), } } diff --git a/parser/src/parser/file.rs b/parser/src/parser/file.rs index 98f81fd938..0451c6ab1d 100644 --- a/parser/src/parser/file.rs +++ b/parser/src/parser/file.rs @@ -91,12 +91,7 @@ impl ParserContext { ))); } - if start.col_stop != name.span.col_start { - let mut error_span = &start + &name.span; - error_span.col_start = start.col_stop - 1; - error_span.col_stop = name.span.col_start - 1; - return Err(SyntaxError::unexpected_whitespace("@", &name.name, &error_span)); - } + unexpected_whitespace(&start, &name.span, &name.name, "@")?; let end_span; let arguments = if self.eat(Token::LeftParen).is_some() { diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index c217089d89..90b914aa02 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -41,3 +41,14 @@ pub fn parse(path: &str, source: &str) -> SyntaxResult { tokens.parse_program() } + +pub fn unexpected_whitespace(left_span: &Span, right_span: &Span, left: &str, right: &str) -> SyntaxResult<()> { + if left_span.col_stop != right_span.col_start { + let mut error_span = left_span + right_span; + error_span.col_start = left_span.col_stop - 1; + error_span.col_stop = right_span.col_start - 1; + return Err(SyntaxError::unexpected_whitespace(left, right, &error_span)); + } + + Ok(()) +} From b51471a6a828f14923bae42fe4b379cad218b4c5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 5 Apr 2021 10:40:52 +0000 Subject: [PATCH 065/108] Bump abnf from 0.10.0 to 0.10.1 Bumps [abnf](https://github.com/duesee/abnf) from 0.10.0 to 0.10.1. - [Release notes](https://github.com/duesee/abnf/releases) - [Commits](https://github.com/duesee/abnf/commits) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- grammar/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d21daf157d..8a58d96ce5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "abnf" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020babd9b431b239cffff9eb1e49d8cad5f3581674d3938540801e633a3b5f69" +checksum = "eb23c378acfcb46052bd7d1a6119d8d608d4c12ac6c72cb1d9c4e85bc2cb2bb7" dependencies = [ "abnf-core", "nom 6.1.2", diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index e9dcc5a044..5360ec457c 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -14,5 +14,5 @@ keywords = [ ] [dependencies] -abnf = "0.10.0" +abnf = "0.10.1" anyhow = "1.0" From 044dc96e58a4e9a71aa63a23f7f310a20072acf4 Mon Sep 17 00:00:00 2001 From: damirka Date: Mon, 5 Apr 2021 16:08:54 +0300 Subject: [PATCH 066/108] adds tests for outputfile --- Cargo.lock | 1 + compiler/Cargo.toml | 3 +++ compiler/src/errors/output_file.rs | 3 --- compiler/src/output/output_file.rs | 36 +++++++++++++++++++----------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 520a984b45..caef39fb6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1269,6 +1269,7 @@ dependencies = [ "snarkvm-gadgets", "snarkvm-r1cs", "snarkvm-utilities", + "tempfile", "thiserror", "tracing", ] diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 1c7a47cea4..01c90ad6aa 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -114,6 +114,9 @@ default-features = false version = "0.2.1" default-features = false +[dev-dependencies.tempfile] +version = "3.0.4" + [features] default = [ ] ci_skip = [ "leo-ast/ci_skip" ] diff --git a/compiler/src/errors/output_file.rs b/compiler/src/errors/output_file.rs index c8b18185d6..014327c3ad 100644 --- a/compiler/src/errors/output_file.rs +++ b/compiler/src/errors/output_file.rs @@ -21,9 +21,6 @@ pub enum OutputFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - #[error("creating: {}", _0)] - Creating(io::Error), - #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), diff --git a/compiler/src/output/output_file.rs b/compiler/src/output/output_file.rs index f9dd6eeda1..48d1b8bac4 100644 --- a/compiler/src/output/output_file.rs +++ b/compiler/src/output/output_file.rs @@ -42,19 +42,6 @@ impl OutputFile { } } - pub fn exists_at(&self, path: &Path) -> bool { - let path = self.setup_file_path(path); - path.exists() - } - - /// Reads the output register variables from the given file path if it exists. - pub fn read_from(&self, path: &Path) -> Result { - let path = self.setup_file_path(path); - - let output = fs::read_to_string(&path).map_err(|_| OutputFileError::FileReadError(path.into_owned()))?; - Ok(output) - } - /// Writes output to a file. pub fn write(&self, path: &Path, bytes: &[u8]) -> Result<(), OutputFileError> { // create output file @@ -88,3 +75,26 @@ impl OutputFile { path } } + +#[cfg(test)] +mod test_output_file { + use crate::{OutputFile, OUTPUTS_DIRECTORY_NAME}; + use std::{error::Error, fs}; + + #[test] + fn test_all() -> Result<(), Box> { + let dir = tempfile::tempdir()?; + let file = OutputFile::new("test"); + let path = dir.path(); + + assert!(file.write(path, Default::default()).is_err()); + assert!(file.remove(path)? == false); + + fs::create_dir(dir.path().join(OUTPUTS_DIRECTORY_NAME))?; + + assert!(file.write(path, Default::default()).is_ok()); + assert!(file.remove(path)? == true); + + Ok(()) + } +} From a588c1810066520d20ad583429d9e3b16a5a8750 Mon Sep 17 00:00:00 2001 From: damirka Date: Mon, 5 Apr 2021 16:39:38 +0300 Subject: [PATCH 067/108] clippy --- compiler/src/output/output_file.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/output/output_file.rs b/compiler/src/output/output_file.rs index 48d1b8bac4..4fc4c2c3e6 100644 --- a/compiler/src/output/output_file.rs +++ b/compiler/src/output/output_file.rs @@ -88,12 +88,12 @@ mod test_output_file { let path = dir.path(); assert!(file.write(path, Default::default()).is_err()); - assert!(file.remove(path)? == false); + assert!(!file.remove(path)?); fs::create_dir(dir.path().join(OUTPUTS_DIRECTORY_NAME))?; assert!(file.write(path, Default::default()).is_ok()); - assert!(file.remove(path)? == true); + assert!(!file.remove(path)?); Ok(()) } From 2578be42876900991b0209400a45310b26480b81 Mon Sep 17 00:00:00 2001 From: damirka Date: Mon, 5 Apr 2021 19:37:16 +0300 Subject: [PATCH 068/108] fix test --- compiler/src/output/output_file.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/output/output_file.rs b/compiler/src/output/output_file.rs index 4fc4c2c3e6..b9b2570baf 100644 --- a/compiler/src/output/output_file.rs +++ b/compiler/src/output/output_file.rs @@ -88,12 +88,12 @@ mod test_output_file { let path = dir.path(); assert!(file.write(path, Default::default()).is_err()); - assert!(!file.remove(path)?); + assert!(!(file.remove(path)?)); fs::create_dir(dir.path().join(OUTPUTS_DIRECTORY_NAME))?; assert!(file.write(path, Default::default()).is_ok()); - assert!(!file.remove(path)?); + assert!(file.remove(path)?); Ok(()) } From f0ce9d400e3c8cd108d01245653b903ca9d60b31 Mon Sep 17 00:00:00 2001 From: gluax Date: Mon, 5 Apr 2021 12:54:27 -0400 Subject: [PATCH 069/108] testing the changes --- compiler/tests/field/mod.rs | 8 ++++++++ compiler/tests/field/no_space_between_literal.leo | 3 +++ compiler/tests/group/mod.rs | 8 ++++++++ compiler/tests/group/no_space_between_literal.leo | 3 +++ compiler/tests/integers/i8/mod.rs | 8 ++++++++ compiler/tests/integers/i8/no_space_between_literal.leo | 3 +++ 6 files changed, 33 insertions(+) create mode 100644 compiler/tests/field/no_space_between_literal.leo create mode 100644 compiler/tests/group/no_space_between_literal.leo create mode 100644 compiler/tests/integers/i8/no_space_between_literal.leo diff --git a/compiler/tests/field/mod.rs b/compiler/tests/field/mod.rs index 2a768450d6..f5ccb6c116 100644 --- a/compiler/tests/field/mod.rs +++ b/compiler/tests/field/mod.rs @@ -74,6 +74,14 @@ fn test_field() { assert_satisfied(program) } +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let mut program = parse_program(program_string).unwrap(); + + expect_compiler_error(program) +} + #[test] fn test_add() { use std::ops::Add; diff --git a/compiler/tests/field/no_space_between_literal.leo b/compiler/tests/field/no_space_between_literal.leo new file mode 100644 index 0000000000..9ac9dcd5db --- /dev/null +++ b/compiler/tests/field/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const f = 1 field; +} \ No newline at end of file diff --git a/compiler/tests/group/mod.rs b/compiler/tests/group/mod.rs index f40cad73f6..f4cf84448c 100644 --- a/compiler/tests/group/mod.rs +++ b/compiler/tests/group/mod.rs @@ -45,6 +45,14 @@ pub fn group_element_to_input_value(g: EdwardsAffine) -> GroupValue { }) } +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let mut program = parse_program(program_string).unwrap(); + + expect_compiler_error(program) +} + #[test] fn test_one() { let program_string = include_str!("one.leo"); diff --git a/compiler/tests/group/no_space_between_literal.leo b/compiler/tests/group/no_space_between_literal.leo new file mode 100644 index 0000000000..af53e5dffe --- /dev/null +++ b/compiler/tests/group/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const g = (0,1) group; +} \ No newline at end of file diff --git a/compiler/tests/integers/i8/mod.rs b/compiler/tests/integers/i8/mod.rs index 9133a72248..5073dda460 100644 --- a/compiler/tests/integers/i8/mod.rs +++ b/compiler/tests/integers/i8/mod.rs @@ -131,3 +131,11 @@ fn test_i8_console_assert() { fn test_i8_ternary() { TestI8::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/i8/no_space_between_literal.leo b/compiler/tests/integers/i8/no_space_between_literal.leo new file mode 100644 index 0000000000..7a8eda7ef9 --- /dev/null +++ b/compiler/tests/integers/i8/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 i8; +} \ No newline at end of file From 38c36cc30506df675baf6715c4c587cf262651c0 Mon Sep 17 00:00:00 2001 From: gluax Date: Mon, 5 Apr 2021 12:59:08 -0400 Subject: [PATCH 070/108] tests for all the integers --- compiler/tests/integers/i128/mod.rs | 8 ++++++++ compiler/tests/integers/i128/no_space_between_literal.leo | 3 +++ compiler/tests/integers/i16/mod.rs | 8 ++++++++ compiler/tests/integers/i16/no_space_between_literal.leo | 3 +++ compiler/tests/integers/i32/mod.rs | 8 ++++++++ compiler/tests/integers/i32/no_space_between_literal.leo | 3 +++ compiler/tests/integers/i64/mod.rs | 8 ++++++++ compiler/tests/integers/i64/no_space_between_literal.leo | 3 +++ compiler/tests/integers/u128/mod.rs | 8 ++++++++ compiler/tests/integers/u128/no_space_between_literal.leo | 3 +++ compiler/tests/integers/u16/mod.rs | 8 ++++++++ compiler/tests/integers/u16/no_space_between_literal.leo | 3 +++ compiler/tests/integers/u32/mod.rs | 8 ++++++++ compiler/tests/integers/u32/no_space_between_literal.leo | 3 +++ compiler/tests/integers/u64/mod.rs | 8 ++++++++ compiler/tests/integers/u64/no_space_between_literal.leo | 3 +++ compiler/tests/integers/u8/mod.rs | 8 ++++++++ compiler/tests/integers/u8/no_space_between_literal.leo | 3 +++ 18 files changed, 99 insertions(+) create mode 100644 compiler/tests/integers/i128/no_space_between_literal.leo create mode 100644 compiler/tests/integers/i16/no_space_between_literal.leo create mode 100644 compiler/tests/integers/i32/no_space_between_literal.leo create mode 100644 compiler/tests/integers/i64/no_space_between_literal.leo create mode 100644 compiler/tests/integers/u128/no_space_between_literal.leo create mode 100644 compiler/tests/integers/u16/no_space_between_literal.leo create mode 100644 compiler/tests/integers/u32/no_space_between_literal.leo create mode 100644 compiler/tests/integers/u64/no_space_between_literal.leo create mode 100644 compiler/tests/integers/u8/no_space_between_literal.leo diff --git a/compiler/tests/integers/i128/mod.rs b/compiler/tests/integers/i128/mod.rs index e62e07260e..ead011f14e 100644 --- a/compiler/tests/integers/i128/mod.rs +++ b/compiler/tests/integers/i128/mod.rs @@ -132,3 +132,11 @@ fn test_i128_assert_eq() { fn test_i128_ternary() { TestI128::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/i128/no_space_between_literal.leo b/compiler/tests/integers/i128/no_space_between_literal.leo new file mode 100644 index 0000000000..3142fb5724 --- /dev/null +++ b/compiler/tests/integers/i128/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 i128; +} \ No newline at end of file diff --git a/compiler/tests/integers/i16/mod.rs b/compiler/tests/integers/i16/mod.rs index 49b45f5b3e..6f415a0877 100644 --- a/compiler/tests/integers/i16/mod.rs +++ b/compiler/tests/integers/i16/mod.rs @@ -131,3 +131,11 @@ fn test_i16_console_assert() { fn test_i16_ternary() { TestI16::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/i16/no_space_between_literal.leo b/compiler/tests/integers/i16/no_space_between_literal.leo new file mode 100644 index 0000000000..96c6b2a914 --- /dev/null +++ b/compiler/tests/integers/i16/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 i16; +} \ No newline at end of file diff --git a/compiler/tests/integers/i32/mod.rs b/compiler/tests/integers/i32/mod.rs index ee9e25701a..b8a6925ac2 100644 --- a/compiler/tests/integers/i32/mod.rs +++ b/compiler/tests/integers/i32/mod.rs @@ -131,3 +131,11 @@ fn test_i32_console_assert() { fn test_i32_ternary() { TestI32::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/i32/no_space_between_literal.leo b/compiler/tests/integers/i32/no_space_between_literal.leo new file mode 100644 index 0000000000..845a7f403e --- /dev/null +++ b/compiler/tests/integers/i32/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 i32; +} \ No newline at end of file diff --git a/compiler/tests/integers/i64/mod.rs b/compiler/tests/integers/i64/mod.rs index 066ac9956f..ccfb06ce68 100644 --- a/compiler/tests/integers/i64/mod.rs +++ b/compiler/tests/integers/i64/mod.rs @@ -132,3 +132,11 @@ fn test_i64_console_assert() { fn test_i64_ternary() { TestI64::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/i64/no_space_between_literal.leo b/compiler/tests/integers/i64/no_space_between_literal.leo new file mode 100644 index 0000000000..7fb6ea9e62 --- /dev/null +++ b/compiler/tests/integers/i64/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 i64; +} \ No newline at end of file diff --git a/compiler/tests/integers/u128/mod.rs b/compiler/tests/integers/u128/mod.rs index 2c110af0a5..38677dcb29 100644 --- a/compiler/tests/integers/u128/mod.rs +++ b/compiler/tests/integers/u128/mod.rs @@ -116,3 +116,11 @@ fn test_u128_console_assert() { fn test_u128_ternary() { TestU128::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/u128/no_space_between_literal.leo b/compiler/tests/integers/u128/no_space_between_literal.leo new file mode 100644 index 0000000000..fc48e7f1ae --- /dev/null +++ b/compiler/tests/integers/u128/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 u128; +} \ No newline at end of file diff --git a/compiler/tests/integers/u16/mod.rs b/compiler/tests/integers/u16/mod.rs index b4b202b9da..33f88452c1 100644 --- a/compiler/tests/integers/u16/mod.rs +++ b/compiler/tests/integers/u16/mod.rs @@ -116,3 +116,11 @@ fn test_u16_console_assert() { fn test_u16_ternary() { TestU16::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/u16/no_space_between_literal.leo b/compiler/tests/integers/u16/no_space_between_literal.leo new file mode 100644 index 0000000000..34e125cfc6 --- /dev/null +++ b/compiler/tests/integers/u16/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 u16; +} \ No newline at end of file diff --git a/compiler/tests/integers/u32/mod.rs b/compiler/tests/integers/u32/mod.rs index 920fc6ed5b..7f2d76d198 100644 --- a/compiler/tests/integers/u32/mod.rs +++ b/compiler/tests/integers/u32/mod.rs @@ -116,3 +116,11 @@ fn test_u32_console_assert() { fn test_u32_ternary() { TestU32::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/u32/no_space_between_literal.leo b/compiler/tests/integers/u32/no_space_between_literal.leo new file mode 100644 index 0000000000..83b3caca55 --- /dev/null +++ b/compiler/tests/integers/u32/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 u32; +} \ No newline at end of file diff --git a/compiler/tests/integers/u64/mod.rs b/compiler/tests/integers/u64/mod.rs index ec86c868f1..1a2af24ddd 100644 --- a/compiler/tests/integers/u64/mod.rs +++ b/compiler/tests/integers/u64/mod.rs @@ -116,3 +116,11 @@ fn test_u64_console_assert() { fn test_u64_ternary() { TestU64::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/u64/no_space_between_literal.leo b/compiler/tests/integers/u64/no_space_between_literal.leo new file mode 100644 index 0000000000..852fd5c2aa --- /dev/null +++ b/compiler/tests/integers/u64/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 u64; +} \ No newline at end of file diff --git a/compiler/tests/integers/u8/mod.rs b/compiler/tests/integers/u8/mod.rs index a61e28246d..f1fb2b0fab 100644 --- a/compiler/tests/integers/u8/mod.rs +++ b/compiler/tests/integers/u8/mod.rs @@ -116,3 +116,11 @@ fn test_u8_console_assert() { fn test_u8_ternary() { TestU8::test_ternary(); } + +#[test] +fn test_no_space_between_literal() { + let program_string = include_str!("no_space_between_literal.leo"); + let program = parse_program(program_string); + + assert!(program.is_err()); +} diff --git a/compiler/tests/integers/u8/no_space_between_literal.leo b/compiler/tests/integers/u8/no_space_between_literal.leo new file mode 100644 index 0000000000..64eba2a083 --- /dev/null +++ b/compiler/tests/integers/u8/no_space_between_literal.leo @@ -0,0 +1,3 @@ +function main() { + const i = 1 u8; +} \ No newline at end of file From b535a5fde3a8bbbcee6a6b35ecc2798ab431b252 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 5 Apr 2021 13:55:05 -0700 Subject: [PATCH 071/108] [ABNF] Allow spaces in affine group literals. --- grammar/abnf-grammar.md | 235 +++++++++++++++++---------------------- grammar/abnf-grammar.txt | 105 ++++++++--------- 2 files changed, 146 insertions(+), 194 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index eb587deea0..29b757e6a4 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -494,7 +494,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline), [space](#user-content-space)_; +Go to: _[newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space)_; There are two kinds of comments in Leo, as in other languages. @@ -512,7 +512,7 @@ the ones used in the Java language specification. comment = block-comment / end-of-line-comment ``` -Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; +Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_; @@ -529,7 +529,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star / not-star rest-of-block-comment ``` -Go to: _[not-star](#user-content-not-star), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_; @@ -539,7 +539,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_; @@ -614,7 +614,7 @@ lowercase-letter = %x61-7A ; a-z letter = uppercase-letter / lowercase-letter ``` -Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_; +Go to: _[uppercase-letter](#user-content-uppercase-letter), [lowercase-letter](#user-content-lowercase-letter)_; An identifier is a non-empty sequence of letters, digits, and underscores, @@ -784,12 +784,8 @@ Go to: _[integer](#user-content-integer)_; There are two kinds of group literals. One is a single integer followed by the type of group elements, which denotes the scalar product of the generator point by the integer. -The other is a pair of integer coordinates, -which are reduced modulo the prime to identify a point, -which must be on the elliptic curve. -It is also allowed to omit one (not both) coordinates, -with an indication of how to infer the missing coordinate -(i.e. sign high, sign low, or inferred). +The other kind is not a token because it allows some whitespace inside; +therefore, it is defined in the syntactic grammar. ```abnf @@ -799,97 +795,6 @@ product-group-literal = integer "group" Go to: _[integer](#user-content-integer)_; - -```abnf -group-coordinate = integer / "+" / "-" / "_" -``` - -Go to: _[integer](#user-content-integer)_; - - - -```abnf -affine-group-literal = "(" group-coordinate "," group-coordinate ")" "group" -``` - -Go to: _[group-coordinate](#user-content-group-coordinate)_; - - - -```abnf -group-literal = product-group-literal / affine-group-literal -``` - -Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_; - - -Note that the rule for group literals above -allows no whitespace between coordinates. -If we want to allow whitespace, -e.g. '(3, 4)group' as opposed to requiring '(3,4)group', -then we should define affine group literals -in the syntactic grammar instead of in the lexical grammar. -We should have a notion of atomic literal in the lexical grammar, -and (non-atomic) literal in the syntactic grammar. -The lexical grammar should define a token for ')group' -if we want no whitespace between the closing parenthesis and 'group'. -More precisely, the rule for 'literal' below in the lexical grammar -would be replaced with - - - -``` -atomic-literal = ... / product-group-literal -``` - - - -where the '...' stands for all the '...-literal' alternatives -in the current rule for 'literal' below, except 'group-literal'. -Furthermore, the rule for 'symbol' below in the lexical grammar -would be extended to - - - -``` -symbol = ... / ")group" -``` - - - -where '...' stands for the current definiens of the rule. -We would also have to adjust the rule for 'token' below in the lexical grammar -to reference 'atomic-literal' instead of 'literal' in the definiens. -We would then add to the syntactic grammar the following rules - - - -``` -affine-group-literal = "(" group-coordinate "," group-coordinate ")group" -``` - - - -``` -literal = atomic-literal / affine-group-literal -``` - - - -which would now define literals in the syntactic grammar. -Note that now an affine group literal would have the form - - - -``` -( , )group -``` - - - -where is optional whitespace; -however, no whitespace is allowed between the closing ')' and 'group'. - Boolean literals are the usual two. @@ -910,18 +815,18 @@ Go to: _[address](#user-content-address)_; The ones above are all the literals, as defined by the following rule. - + ```abnf -literal = untyped-literal - / unsigned-literal - / signed-literal - / field-literal - / group-literal - / boolean-literal - / address-literal +atomic-literal = untyped-literal + / unsigned-literal + / signed-literal + / field-literal + / product-group-literal + / boolean-literal + / address-literal ``` -Go to: _[unsigned-literal](#user-content-unsigned-literal), [untyped-literal](#user-content-untyped-literal), [field-literal](#user-content-field-literal), [group-literal](#user-content-group-literal), [address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [signed-literal](#user-content-signed-literal)_; +Go to: _[unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [address-literal](#user-content-address-literal), [signed-literal](#user-content-signed-literal), [product-group-literal](#user-content-product-group-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -929,6 +834,14 @@ it remains to define tokens for non-alphanumeric symbols such as "+" and "(". Different programming languages used different terminologies for these, e.g. operators, separators, punctuators, etc. Here we use 'symbol', for all of them, but we can do something different. +We also include a token consisting of +a closing parenthesis immediately followed by 'group': +as defined in the syntactic grammar, +this is the final part of an affine group literal. +Even though it includes letters, +it seems appropriate to still consider it a symbol, +particularly since it starts with a symbol. + We could give names to all of these symbols, via rules such as @@ -969,6 +882,7 @@ symbol = "!" / "&&" / "||" / "{" / "}" / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" / "->" / "_" + / ")group" ``` Everything defined above, other than comments and whitespace, @@ -978,14 +892,14 @@ is a token, as defined by the following rule. ```abnf token = keyword / identifier - / literal + / atomic-literal / package-name / formatted-string / annotation-name / symbol ``` -Go to: _[literal](#user-content-literal), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string), [symbol](#user-content-symbol), [identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name)_; +Go to: _[identifier](#user-content-identifier), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [symbol](#user-content-symbol), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string), [keyword](#user-content-keyword)_; @@ -1021,7 +935,7 @@ signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type ``` -Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; +Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; The integer types, along with the field and group types, @@ -1063,7 +977,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type)_; +Go to: _[arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -1125,7 +1039,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type)_; +Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_; Scalar and aggregate types form all the types. @@ -1135,7 +1049,58 @@ Scalar and aggregate types form all the types. type = scalar-type / aggregate-type ``` -Go to: _[scalar-type](#user-content-scalar-type), [aggregate-type](#user-content-aggregate-type)_; +Go to: _[aggregate-type](#user-content-aggregate-type), [scalar-type](#user-content-scalar-type)_; + + +The lexical grammar above defines product group literals. +The other kind of group literal is a pair of integer coordinates, +which are reduced modulo the prime to identify a point, +which must be on the elliptic curve. +It is also allowed to omit one (not both) coordinates, +with an indication of how to infer the missing coordinate +(i.e. sign high, sign low, or inferred). +This is an affine group literal, +because it consists of affine point coordinates. + + +```abnf +group-coordinate = integer / "+" / "-" / "_" +``` + +Go to: _[integer](#user-content-integer)_; + + + +```abnf +affine-group-literal = "(" group-coordinate "," group-coordinate ")" "group" +``` + +Go to: _[group-coordinate](#user-content-group-coordinate)_; + + +A literal is either an atomic one or an affine group literal. +Here 'atomic' refers to being a token or not, +since no whitespace is allowed within a token. + + +```abnf +literal = atomic-literal / affine-group-literal +``` + +Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_; + + +The following rule is not directly referenced in the rules for expressions +(which reference 'literal' instead), +but it is useful to establish terminology: +a group literal is either a product group literal or an affine group literal. + + +```abnf +group-literal = product-group-literal / affine-group-literal +``` + +Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_; As often done in grammatical language syntax specifications, @@ -1166,7 +1131,7 @@ primary-expression = identifier / function-call ``` -Go to: _[function-call](#user-content-function-call), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [tuple-expression](#user-content-tuple-expression)_; +Go to: _[function-call](#user-content-function-call), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [tuple-expression](#user-content-tuple-expression)_; There are tuple expressions to construct and deconstruct tuples. @@ -1235,7 +1200,7 @@ Go to: _[expression](#user-content-expression)_; array-repeat-construction = "[" expression ";" array-dimensions "]" ``` -Go to: _[expression](#user-content-expression), [array-dimensions](#user-content-array-dimensions)_; +Go to: _[array-dimensions](#user-content-array-dimensions), [expression](#user-content-expression)_; @@ -1243,7 +1208,7 @@ Go to: _[expression](#user-content-expression), [array-dimensions](#user-content array-construction = array-inline-construction / array-repeat-construction ``` -Go to: _[array-inline-construction](#user-content-array-inline-construction), [array-repeat-construction](#user-content-array-repeat-construction)_; +Go to: _[array-repeat-construction](#user-content-array-repeat-construction), [array-inline-construction](#user-content-array-inline-construction)_; @@ -1273,7 +1238,7 @@ circuit-construction = circuit-type "{" "}" ``` -Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; +Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_; @@ -1331,7 +1296,7 @@ unary-expression = postfix-expression / "-" unary-expression ``` -Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_; +Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_; Next in the operator precedence is casting. @@ -1375,7 +1340,7 @@ additive-expression = multiplicative-expression / additive-expression "-" multiplicative-expression ``` -Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; +Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; Next in the precedence order are ordering relations. @@ -1425,7 +1390,7 @@ disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression ``` -Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; +Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; Finally we have conditional expressions. @@ -1438,7 +1403,7 @@ conditional-expression = disjunctive-expression ":" conditional-expression ``` -Go to: _[conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; +Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_; These are all the expressions. @@ -1471,7 +1436,7 @@ statement = expression-statement / block ``` -Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement), [conditional-statement](#user-content-conditional-statement), [return-statement](#user-content-return-statement), [expression-statement](#user-content-expression-statement)_; +Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [expression-statement](#user-content-expression-statement), [loop-statement](#user-content-loop-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block)_; @@ -1514,7 +1479,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; @@ -1547,7 +1512,7 @@ conditional-statement = branch / branch "else" conditional-statement ``` -Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_; +Go to: _[conditional-statement](#user-content-conditional-statement), [branch](#user-content-branch), [block](#user-content-block)_; A loop statement implicitly defines a loop variable @@ -1576,7 +1541,7 @@ assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" assignment-statement = expression assignment-operator expression ";" ``` -Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [assignment-operator](#user-content-assignment-operator)_; Console statements start with the 'console' keyword, @@ -1632,7 +1597,7 @@ Go to: _[formatted-string](#user-content-formatted-string)_; print-call = print-function print-arguments ``` -Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; +Go to: _[print-arguments](#user-content-print-arguments), [print-function](#user-content-print-function)_; An annotation consists of an annotation name (which starts with '@') @@ -1645,7 +1610,7 @@ annotation = annotation-name [ "(" identifier *( "," identifier ) ")" ] ``` -Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_; +Go to: _[annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier)_; A function declaration defines a function. @@ -1667,7 +1632,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[function-parameters](#user-content-function-parameters), [type](#user-content-type), [block](#user-content-block), [identifier](#user-content-identifier)_; +Go to: _[type](#user-content-type), [function-parameters](#user-content-function-parameters), [identifier](#user-content-identifier), [block](#user-content-block)_; @@ -1678,7 +1643,7 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[input-parameter](#user-content-input-parameter), [function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter)_; +Go to: _[function-inputs](#user-content-function-inputs), [input-parameter](#user-content-input-parameter), [self-parameter](#user-content-self-parameter)_; @@ -1726,7 +1691,7 @@ Go to: _[member-variable-declaration](#user-content-member-variable-declaration) member-variable-declaration = identifier ":" type ``` -Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; @@ -1794,7 +1759,7 @@ declaration = import-declaration / circuit-declaration ``` -Go to: _[import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_; +Go to: _[function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration)_; diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index a397d1630b..cca93278d3 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -540,60 +540,11 @@ field-literal = integer %s"field" ; There are two kinds of group literals. ; One is a single integer followed by the type of group elements, ; which denotes the scalar product of the generator point by the integer. -; The other is a pair of integer coordinates, -; which are reduced modulo the prime to identify a point, -; which must be on the elliptic curve. -; It is also allowed to omit one (not both) coordinates, -; with an indication of how to infer the missing coordinate -; (i.e. sign high, sign low, or inferred). +; The other kind is not a token because it allows some whitespace inside; +; therefore, it is defined in the syntactic grammar. product-group-literal = integer %s"group" -group-coordinate = integer / "+" / "-" / "_" - -affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" - -group-literal = product-group-literal / affine-group-literal - -; Note that the rule for group literals above -; allows no whitespace between coordinates. -; If we want to allow whitespace, -; e.g. '(3, 4)group' as opposed to requiring '(3,4)group', -; then we should define affine group literals -; in the syntactic grammar instead of in the lexical grammar. -; We should have a notion of atomic literal in the lexical grammar, -; and (non-atomic) literal in the syntactic grammar. -; The lexical grammar should define a token for ')group' -; if we want no whitespace between the closing parenthesis and 'group'. -; More precisely, the rule for 'literal' below in the lexical grammar -; would be replaced with -; -; atomic-literal = ... / product-group-literal -; -; where the '...' stands for all the '...-literal' alternatives -; in the current rule for 'literal' below, except 'group-literal'. -; Furthermore, the rule for 'symbol' below in the lexical grammar -; would be extended to -; -; symbol = ... / %s")group" -; -; where '...' stands for the current definiens of the rule. -; We would also have to adjust the rule for 'token' below in the lexical grammar -; to reference 'atomic-literal' instead of 'literal' in the definiens. -; We would then add to the syntactic grammar the following rules -; -; affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" -; -; literal = atomic-literal / affine-group-literal -; -; which would now define literals in the syntactic grammar. -; Note that now an affine group literal would have the form -; -; ( , )group -; -; where is optional whitespace; -; however, no whitespace is allowed between the closing ')' and 'group'. - ; Boolean literals are the usual two. boolean-literal = %s"true" / %s"false" @@ -605,19 +556,27 @@ address-literal = %s"address" "(" address ")" ; The ones above are all the literals, as defined by the following rule. -literal = untyped-literal - / unsigned-literal - / signed-literal - / field-literal - / group-literal - / boolean-literal - / address-literal +atomic-literal = untyped-literal + / unsigned-literal + / signed-literal + / field-literal + / product-group-literal + / boolean-literal + / address-literal ; After defining the (mostly) alphanumeric tokens above, ; it remains to define tokens for non-alphanumeric symbols such as "+" and "(". ; Different programming languages used different terminologies for these, ; e.g. operators, separators, punctuators, etc. ; Here we use 'symbol', for all of them, but we can do something different. +; We also include a token consisting of +; a closing parenthesis immediately followed by 'group': +; as defined in the syntactic grammar, +; this is the final part of an affine group literal. +; Even though it includes letters, +; it seems appropriate to still consider it a symbol, +; particularly since it starts with a symbol. + ; We could give names to all of these symbols, ; via rules such as ; @@ -644,13 +603,14 @@ symbol = "!" / "&&" / "||" / "{" / "}" / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" / "->" / "_" + / %s")group" ; Everything defined above, other than comments and whitespace, ; is a token, as defined by the following rule. token = keyword / identifier - / literal + / atomic-literal / package-name / formatted-string / annotation-name @@ -729,6 +689,33 @@ aggregate-type = tuple-type / array-type / circuit-type type = scalar-type / aggregate-type +; The lexical grammar above defines product group literals. +; The other kind of group literal is a pair of integer coordinates, +; which are reduced modulo the prime to identify a point, +; which must be on the elliptic curve. +; It is also allowed to omit one (not both) coordinates, +; with an indication of how to infer the missing coordinate +; (i.e. sign high, sign low, or inferred). +; This is an affine group literal, +; because it consists of affine point coordinates. + +group-coordinate = integer / "+" / "-" / "_" + +affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" + +; A literal is either an atomic one or an affine group literal. +; Here 'atomic' refers to being a token or not, +; since no whitespace is allowed within a token. + +literal = atomic-literal / affine-group-literal + +; The following rule is not directly referenced in the rules for expressions +; (which reference 'literal' instead), +; but it is useful to establish terminology: +; a group literal is either a product group literal or an affine group literal. + +group-literal = product-group-literal / affine-group-literal + ; As often done in grammatical language syntax specifications, ; we define rules for different kinds of expressions, ; which also defines the relative precedence From 8396014e3287c1a85aa756163e70858b96d6e495 Mon Sep 17 00:00:00 2001 From: Collin Chin Date: Mon, 5 Apr 2021 21:01:49 -0700 Subject: [PATCH 072/108] Update verification_key.rs --- package/src/errors/outputs/verification_key.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/package/src/errors/outputs/verification_key.rs b/package/src/errors/outputs/verification_key.rs index bcf3e8de66..6a9f437b8a 100644 --- a/package/src/errors/outputs/verification_key.rs +++ b/package/src/errors/outputs/verification_key.rs @@ -21,18 +21,11 @@ pub enum VerificationKeyFileError { #[error("{}: {}", _0, _1)] Crate(&'static str, String), - // #[error("creating: {}", _0)] - // Creating(io::Error), #[error("Cannot read from the provided file path - {:?}", _0)] FileReadError(PathBuf), #[error("Cannot remove the provided file - {:?}", _0)] FileRemovalError(PathBuf), - // #[error("Verification key file was corrupted")] - // IncorrectVerificationKey, - - // #[error("writing: {}", _0)] - // Writing(io::Error), } impl From for VerificationKeyFileError { From 5f875a4e933eb7a6a1f3abec77e9aacd2769e64c Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 5 Apr 2021 21:27:37 -0700 Subject: [PATCH 073/108] [ABNF] Allow const self. This still needed to be updated. The rules only supported self and mut self. --- grammar/abnf-grammar.md | 76 +++++++++++++++++++--------------------- grammar/abnf-grammar.txt | 8 ++--- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index 29b757e6a4..bc6bda89e2 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -484,7 +484,7 @@ according to the extra-grammatical rule of the longest sequence. newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; +Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -494,7 +494,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space)_; +Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_; There are two kinds of comments in Leo, as in other languages. @@ -529,7 +529,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star / not-star rest-of-block-comment ``` -Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_; +Go to: _[not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; @@ -539,7 +539,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_; @@ -826,7 +826,7 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [address-literal](#user-content-address-literal), [signed-literal](#user-content-signed-literal), [product-group-literal](#user-content-product-group-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal)_; +Go to: _[signed-literal](#user-content-signed-literal), [unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [untyped-literal](#user-content-untyped-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [product-group-literal](#user-content-product-group-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -899,7 +899,7 @@ token = keyword / symbol ``` -Go to: _[identifier](#user-content-identifier), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [symbol](#user-content-symbol), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string), [keyword](#user-content-keyword)_; +Go to: _[package-name](#user-content-package-name), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [identifier](#user-content-identifier), [atomic-literal](#user-content-atomic-literal), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string)_; @@ -935,7 +935,7 @@ signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type ``` -Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; +Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; The integer types, along with the field and group types, @@ -956,7 +956,7 @@ group-type = "group" arithmetic-type = integer-type / field-type / group-type ``` -Go to: _[field-type](#user-content-field-type), [group-type](#user-content-group-type), [integer-type](#user-content-integer-type)_; +Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_; The arithmetic types, along with the boolean and address types, @@ -977,7 +977,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_; +Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -994,7 +994,7 @@ self-type = "Self" circuit-type = identifier / self-type ``` -Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; A tuple type consists of zero, two, or more component types. @@ -1039,7 +1039,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_; +Go to: _[tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type), [array-type](#user-content-array-type)_; Scalar and aggregate types form all the types. @@ -1049,7 +1049,7 @@ Scalar and aggregate types form all the types. type = scalar-type / aggregate-type ``` -Go to: _[aggregate-type](#user-content-aggregate-type), [scalar-type](#user-content-scalar-type)_; +Go to: _[scalar-type](#user-content-scalar-type), [aggregate-type](#user-content-aggregate-type)_; The lexical grammar above defines product group literals. @@ -1087,7 +1087,7 @@ since no whitespace is allowed within a token. literal = atomic-literal / affine-group-literal ``` -Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_; +Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_; The following rule is not directly referenced in the rules for expressions @@ -1100,7 +1100,7 @@ a group literal is either a product group literal or an affine group literal. group-literal = product-group-literal / affine-group-literal ``` -Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_; +Go to: _[affine-group-literal](#user-content-affine-group-literal), [product-group-literal](#user-content-product-group-literal)_; As often done in grammatical language syntax specifications, @@ -1131,7 +1131,7 @@ primary-expression = identifier / function-call ``` -Go to: _[function-call](#user-content-function-call), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [tuple-expression](#user-content-tuple-expression)_; +Go to: _[tuple-expression](#user-content-tuple-expression), [circuit-expression](#user-content-circuit-expression), [literal](#user-content-literal), [expression](#user-content-expression), [function-call](#user-content-function-call), [identifier](#user-content-identifier), [array-expression](#user-content-array-expression)_; There are tuple expressions to construct and deconstruct tuples. @@ -1208,7 +1208,7 @@ Go to: _[array-dimensions](#user-content-array-dimensions), [expression](#user-c array-construction = array-inline-construction / array-repeat-construction ``` -Go to: _[array-repeat-construction](#user-content-array-repeat-construction), [array-inline-construction](#user-content-array-inline-construction)_; +Go to: _[array-inline-construction](#user-content-array-inline-construction), [array-repeat-construction](#user-content-array-repeat-construction)_; @@ -1238,7 +1238,7 @@ circuit-construction = circuit-type "{" "}" ``` -Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_; +Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; @@ -1246,7 +1246,7 @@ Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#us circuit-inline-element = identifier ":" expression / identifier ``` -Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier)_; @@ -1296,7 +1296,7 @@ unary-expression = postfix-expression / "-" unary-expression ``` -Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_; +Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_; Next in the operator precedence is casting. @@ -1316,7 +1316,7 @@ exponential-expression = cast-expression / exponential-expression "**" cast-expression ``` -Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_; +Go to: _[exponential-expression](#user-content-exponential-expression), [cast-expression](#user-content-cast-expression)_; Next in precedence come multiplication and division, both left-associative. @@ -1340,7 +1340,7 @@ additive-expression = multiplicative-expression / additive-expression "-" multiplicative-expression ``` -Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; +Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; Next in the precedence order are ordering relations. @@ -1368,7 +1368,7 @@ equality-expression = ordering-expression / equality-expression "!=" ordering-expression ``` -Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; +Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_; Next come conjunctive expressions, left-associative. @@ -1403,7 +1403,7 @@ conditional-expression = disjunctive-expression ":" conditional-expression ``` -Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression)_; These are all the expressions. @@ -1436,7 +1436,7 @@ statement = expression-statement / block ``` -Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [expression-statement](#user-content-expression-statement), [loop-statement](#user-content-loop-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block)_; +Go to: _[expression-statement](#user-content-expression-statement), [conditional-statement](#user-content-conditional-statement), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement), [block](#user-content-block), [return-statement](#user-content-return-statement), [variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement)_; @@ -1479,7 +1479,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[expression](#user-content-expression), [type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; +Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression), [type](#user-content-type)_; @@ -1512,7 +1512,7 @@ conditional-statement = branch / branch "else" conditional-statement ``` -Go to: _[conditional-statement](#user-content-conditional-statement), [branch](#user-content-branch), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_; A loop statement implicitly defines a loop variable @@ -1524,7 +1524,7 @@ The body is a block. loop-statement = "for" identifier "in" expression ".." expression block ``` -Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [block](#user-content-block)_; An assignment statement is straightforward. @@ -1597,7 +1597,7 @@ Go to: _[formatted-string](#user-content-formatted-string)_; print-call = print-function print-arguments ``` -Go to: _[print-arguments](#user-content-print-arguments), [print-function](#user-content-print-function)_; +Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; An annotation consists of an annotation name (which starts with '@') @@ -1620,10 +1620,8 @@ The output type is optional (it defaults to the empty tuple type). In general, a function input consists of an identifier and a type, with an optional 'const' modifier. However, functions inside circuits -may start with a 'mut self' or 'self' parameter, -which may be the only parameter in fact. -Furthermore, any function may end with an 'input' parameter, -which may be the only parameter in fact. +may start with a 'mut self' or 'const self' or 'self' parameter. +Furthermore, any function may end with an 'input' parameter. ```abnf @@ -1632,7 +1630,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[type](#user-content-type), [function-parameters](#user-content-function-parameters), [identifier](#user-content-identifier), [block](#user-content-block)_; +Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; @@ -1643,12 +1641,12 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[function-inputs](#user-content-function-inputs), [input-parameter](#user-content-input-parameter), [self-parameter](#user-content-self-parameter)_; +Go to: _[self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter), [function-inputs](#user-content-function-inputs)_; ```abnf -self-parameter = ["mut"] "self" +self-parameter = [ "mut" / "const" ] "self" ``` @@ -1664,7 +1662,7 @@ Go to: _[function-input](#user-content-function-input)_; function-input = [ "const" ] identifier ":" type ``` -Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; @@ -1691,7 +1689,7 @@ Go to: _[member-variable-declaration](#user-content-member-variable-declaration) member-variable-declaration = identifier ":" type ``` -Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; @@ -1712,7 +1710,7 @@ circuit-declaration = *annotation "circuit" identifier "{" member-declaration *( "," member-declaration ) "}" ``` -Go to: _[member-declaration](#user-content-member-declaration), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [member-declaration](#user-content-member-declaration)_; An import declaration consists of the 'import' keyword @@ -1759,7 +1757,7 @@ declaration = import-declaration / circuit-declaration ``` -Go to: _[function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration)_; +Go to: _[circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration)_; diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index cca93278d3..49ba087869 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -1002,10 +1002,8 @@ annotation = annotation-name ; In general, a function input consists of an identifier and a type, ; with an optional 'const' modifier. ; However, functions inside circuits -; may start with a 'mut self' or 'self' parameter, -; which may be the only parameter in fact. -; Furthermore, any function may end with an 'input' parameter, -; which may be the only parameter in fact. +; may start with a 'mut self' or 'const self' or 'self' parameter. +; Furthermore, any function may end with an 'input' parameter. function-declaration = *annotation %s"function" identifier "(" [ function-parameters ] ")" [ "->" type ] @@ -1016,7 +1014,7 @@ function-parameters = self-parameter [ "," input-parameter ] / function-inputs [ "," input-parameter ] / input-parameter -self-parameter = [%s"mut"] %s"self" +self-parameter = [ %s"mut" / %s"const" ] %s"self" function-inputs = function-input *( "," function-input ) From c0ea8798a2afb9b479fbbe631557e13c2be31ac0 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 5 Apr 2021 21:47:28 -0700 Subject: [PATCH 074/108] [ABNF] Remove leftover reference. This was uncovered by running the grammar through the ACL2 build: among other things, the build checks that every nonterminal referenced in the right side of each rule has a definition in the grammar. --- grammar/abnf-grammar.md | 57 ++++++++++++++++++++-------------------- grammar/abnf-grammar.txt | 1 - 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index bc6bda89e2..d21b9ee1a2 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -484,7 +484,7 @@ according to the extra-grammatical rule of the longest sequence. newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; +Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -512,7 +512,7 @@ the ones used in the Java language specification. comment = block-comment / end-of-line-comment ``` -Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_; +Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; @@ -539,7 +539,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_; +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash)_; @@ -826,7 +826,7 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[signed-literal](#user-content-signed-literal), [unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [untyped-literal](#user-content-untyped-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [product-group-literal](#user-content-product-group-literal)_; +Go to: _[signed-literal](#user-content-signed-literal), [product-group-literal](#user-content-product-group-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [unsigned-literal](#user-content-unsigned-literal), [untyped-literal](#user-content-untyped-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -899,7 +899,7 @@ token = keyword / symbol ``` -Go to: _[package-name](#user-content-package-name), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [identifier](#user-content-identifier), [atomic-literal](#user-content-atomic-literal), [annotation-name](#user-content-annotation-name), [formatted-string](#user-content-formatted-string)_; +Go to: _[formatted-string](#user-content-formatted-string), [symbol](#user-content-symbol), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier), [keyword](#user-content-keyword)_; @@ -935,7 +935,7 @@ signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type ``` -Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; +Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; The integer types, along with the field and group types, @@ -977,7 +977,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type)_; +Go to: _[arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -994,7 +994,7 @@ self-type = "Self" circuit-type = identifier / self-type ``` -Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; +Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; A tuple type consists of zero, two, or more component types. @@ -1039,7 +1039,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type), [array-type](#user-content-array-type)_; +Go to: _[tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type)_; Scalar and aggregate types form all the types. @@ -1049,7 +1049,7 @@ Scalar and aggregate types form all the types. type = scalar-type / aggregate-type ``` -Go to: _[scalar-type](#user-content-scalar-type), [aggregate-type](#user-content-aggregate-type)_; +Go to: _[aggregate-type](#user-content-aggregate-type), [scalar-type](#user-content-scalar-type)_; The lexical grammar above defines product group literals. @@ -1128,10 +1128,9 @@ primary-expression = identifier / tuple-expression / array-expression / circuit-expression - / function-call ``` -Go to: _[tuple-expression](#user-content-tuple-expression), [circuit-expression](#user-content-circuit-expression), [literal](#user-content-literal), [expression](#user-content-expression), [function-call](#user-content-function-call), [identifier](#user-content-identifier), [array-expression](#user-content-array-expression)_; +Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [array-expression](#user-content-array-expression), [literal](#user-content-literal), [circuit-expression](#user-content-circuit-expression)_; There are tuple expressions to construct and deconstruct tuples. @@ -1246,7 +1245,7 @@ Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit circuit-inline-element = identifier ":" expression / identifier ``` -Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression)_; @@ -1316,7 +1315,7 @@ exponential-expression = cast-expression / exponential-expression "**" cast-expression ``` -Go to: _[exponential-expression](#user-content-exponential-expression), [cast-expression](#user-content-cast-expression)_; +Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_; Next in precedence come multiplication and division, both left-associative. @@ -1328,7 +1327,7 @@ multiplicative-expression = exponential-expression / multiplicative-expression "/" exponential-expression ``` -Go to: _[exponential-expression](#user-content-exponential-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; +Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [exponential-expression](#user-content-exponential-expression)_; Then there are addition and subtraction, both left-assocative. @@ -1340,7 +1339,7 @@ additive-expression = multiplicative-expression / additive-expression "-" multiplicative-expression ``` -Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; +Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; Next in the precedence order are ordering relations. @@ -1379,7 +1378,7 @@ conjunctive-expression = equality-expression / conjunctive-expression "&&" equality-expression ``` -Go to: _[equality-expression](#user-content-equality-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; +Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [equality-expression](#user-content-equality-expression)_; Next come disjunctive expressions, left-associative. @@ -1403,7 +1402,7 @@ conditional-expression = disjunctive-expression ":" conditional-expression ``` -Go to: _[expression](#user-content-expression), [disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression)_; +Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_; These are all the expressions. @@ -1436,7 +1435,7 @@ statement = expression-statement / block ``` -Go to: _[expression-statement](#user-content-expression-statement), [conditional-statement](#user-content-conditional-statement), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement), [block](#user-content-block), [return-statement](#user-content-return-statement), [variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement)_; +Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block)_; @@ -1479,7 +1478,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression), [type](#user-content-type)_; +Go to: _[expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type)_; @@ -1512,7 +1511,7 @@ conditional-statement = branch / branch "else" conditional-statement ``` -Go to: _[block](#user-content-block), [branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement)_; +Go to: _[branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block)_; A loop statement implicitly defines a loop variable @@ -1524,7 +1523,7 @@ The body is a block. loop-statement = "for" identifier "in" expression ".." expression block ``` -Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [expression](#user-content-expression)_; An assignment statement is straightforward. @@ -1568,7 +1567,7 @@ console-call = assert-call / print-call ``` -Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_; +Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_; @@ -1597,7 +1596,7 @@ Go to: _[formatted-string](#user-content-formatted-string)_; print-call = print-function print-arguments ``` -Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; +Go to: _[print-arguments](#user-content-print-arguments), [print-function](#user-content-print-function)_; An annotation consists of an annotation name (which starts with '@') @@ -1630,7 +1629,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; +Go to: _[function-parameters](#user-content-function-parameters), [type](#user-content-type), [identifier](#user-content-identifier), [block](#user-content-block)_; @@ -1641,7 +1640,7 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter), [function-inputs](#user-content-function-inputs)_; +Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter)_; @@ -1681,7 +1680,7 @@ member-declaration = member-variable-declaration / member-function-declaration ``` -Go to: _[member-variable-declaration](#user-content-member-variable-declaration), [member-function-declaration](#user-content-member-function-declaration)_; +Go to: _[member-function-declaration](#user-content-member-function-declaration), [member-variable-declaration](#user-content-member-variable-declaration)_; @@ -1689,7 +1688,7 @@ Go to: _[member-variable-declaration](#user-content-member-variable-declaration) member-variable-declaration = identifier ":" type ``` -Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; @@ -1739,7 +1738,7 @@ package-path = "*" / "(" package-path *( "," package-path ) [","] ")" ``` -Go to: _[identifier](#user-content-identifier), [package-name](#user-content-package-name), [package-path](#user-content-package-path)_; +Go to: _[identifier](#user-content-identifier), [package-path](#user-content-package-path), [package-name](#user-content-package-name)_; Finally, we define a file as a sequence of zero or more declarations. diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 49ba087869..7a814c6708 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -739,7 +739,6 @@ primary-expression = identifier / tuple-expression / array-expression / circuit-expression - / function-call ; There are tuple expressions to construct and deconstruct tuples. ; A construction consists of zero, two, or more component expressions. From 797e8ceffda55b8b88473638fe4ee81b78d63f59 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 5 Apr 2021 21:53:38 -0700 Subject: [PATCH 075/108] [ABNF] Tweak some layout. Just for consistency with the rest of the file. --- grammar/abnf-grammar.md | 67 ++++++++++++++++++++++------------------ grammar/abnf-grammar.txt | 15 ++++----- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index d21b9ee1a2..caede623b5 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -494,7 +494,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_; +Go to: _[newline](#user-content-newline), [space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab)_; There are two kinds of comments in Leo, as in other languages. @@ -539,7 +539,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_; @@ -826,7 +826,7 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[signed-literal](#user-content-signed-literal), [product-group-literal](#user-content-product-group-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [unsigned-literal](#user-content-unsigned-literal), [untyped-literal](#user-content-untyped-literal)_; +Go to: _[product-group-literal](#user-content-product-group-literal), [boolean-literal](#user-content-boolean-literal), [field-literal](#user-content-field-literal), [address-literal](#user-content-address-literal), [signed-literal](#user-content-signed-literal), [untyped-literal](#user-content-untyped-literal), [unsigned-literal](#user-content-unsigned-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -899,7 +899,7 @@ token = keyword / symbol ``` -Go to: _[formatted-string](#user-content-formatted-string), [symbol](#user-content-symbol), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier), [keyword](#user-content-keyword)_; +Go to: _[annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [identifier](#user-content-identifier), [formatted-string](#user-content-formatted-string)_; @@ -935,7 +935,7 @@ signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type ``` -Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; +Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; The integer types, along with the field and group types, @@ -956,7 +956,7 @@ group-type = "group" arithmetic-type = integer-type / field-type / group-type ``` -Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_; +Go to: _[field-type](#user-content-field-type), [group-type](#user-content-group-type), [integer-type](#user-content-integer-type)_; The arithmetic types, along with the boolean and address types, @@ -977,7 +977,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_; +Go to: _[address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -1039,7 +1039,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type)_; +Go to: _[array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type)_; Scalar and aggregate types form all the types. @@ -1100,7 +1100,7 @@ a group literal is either a product group literal or an affine group literal. group-literal = product-group-literal / affine-group-literal ``` -Go to: _[affine-group-literal](#user-content-affine-group-literal), [product-group-literal](#user-content-product-group-literal)_; +Go to: _[product-group-literal](#user-content-product-group-literal), [affine-group-literal](#user-content-affine-group-literal)_; As often done in grammatical language syntax specifications, @@ -1130,7 +1130,7 @@ primary-expression = identifier / circuit-expression ``` -Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [array-expression](#user-content-array-expression), [literal](#user-content-literal), [circuit-expression](#user-content-circuit-expression)_; +Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [tuple-expression](#user-content-tuple-expression), [array-expression](#user-content-array-expression), [literal](#user-content-literal)_; There are tuple expressions to construct and deconstruct tuples. @@ -1275,14 +1275,21 @@ Postfix expressions have highest precedence. They apply to primary expressions. Contains access expressions for arrays, tuples, and circuits. Contains function call types. + + +```abnf postfix-expression = primary-expression - / postfix-expression "." natural - / postfix-expression "." identifier - / identifier function-arguments - / postfix-expression "." identifier function-arguments - / circuit-type "::" identifier function-arguments - / postfix-expression "[" expression "]" - / postfix-expression "[" [expression] ".." [expression] "]" + / postfix-expression "." natural + / postfix-expression "." identifier + / identifier function-arguments + / postfix-expression "." identifier function-arguments + / circuit-type "::" identifier function-arguments + / postfix-expression "[" expression "]" + / postfix-expression "[" [expression] ".." [expression] "]" +``` + +Go to: _[primary-expression](#user-content-primary-expression), [natural](#user-content-natural), [function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [identifier](#user-content-identifier), [expression](#user-content-expression), [postfix-expression](#user-content-postfix-expression)_; + Unary operators have the highest operator precedence. They apply to postfix expressions @@ -1367,7 +1374,7 @@ equality-expression = ordering-expression / equality-expression "!=" ordering-expression ``` -Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_; +Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; Next come conjunctive expressions, left-associative. @@ -1389,7 +1396,7 @@ disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression ``` -Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; +Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; Finally we have conditional expressions. @@ -1402,7 +1409,7 @@ conditional-expression = disjunctive-expression ":" conditional-expression ``` -Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_; +Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression), [conditional-expression](#user-content-conditional-expression)_; These are all the expressions. @@ -1435,7 +1442,7 @@ statement = expression-statement / block ``` -Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [conditional-statement](#user-content-conditional-statement), [console-statement](#user-content-console-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block)_; +Go to: _[expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [console-statement](#user-content-console-statement), [loop-statement](#user-content-loop-statement), [conditional-statement](#user-content-conditional-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block), [variable-definition-statement](#user-content-variable-definition-statement)_; @@ -1478,7 +1485,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; @@ -1501,7 +1508,7 @@ Note that we require blocks in all branches, not merely statements. branch = "if" expression block ``` -Go to: _[block](#user-content-block), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [block](#user-content-block)_; @@ -1523,7 +1530,7 @@ The body is a block. loop-statement = "for" identifier "in" expression ".." expression block ``` -Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [expression](#user-content-expression)_; +Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [block](#user-content-block)_; An assignment statement is straightforward. @@ -1540,7 +1547,7 @@ assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" assignment-statement = expression assignment-operator expression ";" ``` -Go to: _[expression](#user-content-expression), [assignment-operator](#user-content-assignment-operator)_; +Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_; Console statements start with the 'console' keyword, @@ -1629,7 +1636,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[function-parameters](#user-content-function-parameters), [type](#user-content-type), [identifier](#user-content-identifier), [block](#user-content-block)_; +Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; @@ -1640,7 +1647,7 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter)_; +Go to: _[input-parameter](#user-content-input-parameter), [self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs)_; @@ -1688,7 +1695,7 @@ Go to: _[member-function-declaration](#user-content-member-function-declaration) member-variable-declaration = identifier ":" type ``` -Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; @@ -1738,7 +1745,7 @@ package-path = "*" / "(" package-path *( "," package-path ) [","] ")" ``` -Go to: _[identifier](#user-content-identifier), [package-path](#user-content-package-path), [package-name](#user-content-package-name)_; +Go to: _[package-path](#user-content-package-path), [identifier](#user-content-identifier), [package-name](#user-content-package-name)_; Finally, we define a file as a sequence of zero or more declarations. @@ -1756,7 +1763,7 @@ declaration = import-declaration / circuit-declaration ``` -Go to: _[circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration)_; +Go to: _[function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration)_; diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 7a814c6708..d91c09a750 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -816,14 +816,15 @@ function-arguments = "(" [ expression *( "," expression ) ] ")" ; They apply to primary expressions. ; Contains access expressions for arrays, tuples, and circuits. ; Contains function call types. + postfix-expression = primary-expression - / postfix-expression "." natural - / postfix-expression "." identifier - / identifier function-arguments - / postfix-expression "." identifier function-arguments - / circuit-type "::" identifier function-arguments - / postfix-expression "[" expression "]" - / postfix-expression "[" [expression] ".." [expression] "]" + / postfix-expression "." natural + / postfix-expression "." identifier + / identifier function-arguments + / postfix-expression "." identifier function-arguments + / circuit-type "::" identifier function-arguments + / postfix-expression "[" expression "]" + / postfix-expression "[" [expression] ".." [expression] "]" ; Unary operators have the highest operator precedence. ; They apply to postfix expressions From 880f2cd200378ac50fa342bf3ff2a76181518a09 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 5 Apr 2021 21:54:40 -0700 Subject: [PATCH 076/108] [ABNF] Remove explicit author info, as discussed. --- grammar/abnf-grammar.md | 64 +++++++++++++++++++--------------------- grammar/abnf-grammar.txt | 2 -- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index caede623b5..08439bf320 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -5,10 +5,6 @@ Leo Library Copyright (C) 2021 Aleo Systems Inc. - -Author: Alessandro Coglio (acoglio on GitHub) - - -------- @@ -484,7 +480,7 @@ according to the extra-grammatical rule of the longest sequence. newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; +Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -494,7 +490,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[newline](#user-content-newline), [space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab)_; +Go to: _[space](#user-content-space), [newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab)_; There are two kinds of comments in Leo, as in other languages. @@ -512,7 +508,7 @@ the ones used in the Java language specification. comment = block-comment / end-of-line-comment ``` -Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; +Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_; @@ -529,7 +525,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star / not-star rest-of-block-comment ``` -Go to: _[not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star)_; @@ -539,7 +535,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_; +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash)_; @@ -614,7 +610,7 @@ lowercase-letter = %x61-7A ; a-z letter = uppercase-letter / lowercase-letter ``` -Go to: _[uppercase-letter](#user-content-uppercase-letter), [lowercase-letter](#user-content-lowercase-letter)_; +Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_; An identifier is a non-empty sequence of letters, digits, and underscores, @@ -826,7 +822,7 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[product-group-literal](#user-content-product-group-literal), [boolean-literal](#user-content-boolean-literal), [field-literal](#user-content-field-literal), [address-literal](#user-content-address-literal), [signed-literal](#user-content-signed-literal), [untyped-literal](#user-content-untyped-literal), [unsigned-literal](#user-content-unsigned-literal)_; +Go to: _[address-literal](#user-content-address-literal), [untyped-literal](#user-content-untyped-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [unsigned-literal](#user-content-unsigned-literal), [product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -899,7 +895,7 @@ token = keyword / symbol ``` -Go to: _[annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [identifier](#user-content-identifier), [formatted-string](#user-content-formatted-string)_; +Go to: _[identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [formatted-string](#user-content-formatted-string), [annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal), [symbol](#user-content-symbol)_; @@ -956,7 +952,7 @@ group-type = "group" arithmetic-type = integer-type / field-type / group-type ``` -Go to: _[field-type](#user-content-field-type), [group-type](#user-content-group-type), [integer-type](#user-content-integer-type)_; +Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_; The arithmetic types, along with the boolean and address types, @@ -977,7 +973,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type)_; +Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -994,7 +990,7 @@ self-type = "Self" circuit-type = identifier / self-type ``` -Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; A tuple type consists of zero, two, or more component types. @@ -1039,7 +1035,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type)_; +Go to: _[tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type), [array-type](#user-content-array-type)_; Scalar and aggregate types form all the types. @@ -1130,7 +1126,7 @@ primary-expression = identifier / circuit-expression ``` -Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [tuple-expression](#user-content-tuple-expression), [array-expression](#user-content-array-expression), [literal](#user-content-literal)_; +Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [expression](#user-content-expression)_; There are tuple expressions to construct and deconstruct tuples. @@ -1199,7 +1195,7 @@ Go to: _[expression](#user-content-expression)_; array-repeat-construction = "[" expression ";" array-dimensions "]" ``` -Go to: _[array-dimensions](#user-content-array-dimensions), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [array-dimensions](#user-content-array-dimensions)_; @@ -1245,7 +1241,7 @@ Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit circuit-inline-element = identifier ":" expression / identifier ``` -Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier)_; @@ -1288,7 +1284,7 @@ postfix-expression = primary-expression / postfix-expression "[" [expression] ".." [expression] "]" ``` -Go to: _[primary-expression](#user-content-primary-expression), [natural](#user-content-natural), [function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [identifier](#user-content-identifier), [expression](#user-content-expression), [postfix-expression](#user-content-postfix-expression)_; +Go to: _[postfix-expression](#user-content-postfix-expression), [natural](#user-content-natural), [primary-expression](#user-content-primary-expression), [function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [identifier](#user-content-identifier), [expression](#user-content-expression)_; Unary operators have the highest operator precedence. @@ -1374,7 +1370,7 @@ equality-expression = ordering-expression / equality-expression "!=" ordering-expression ``` -Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; +Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_; Next come conjunctive expressions, left-associative. @@ -1396,7 +1392,7 @@ disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression ``` -Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; +Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; Finally we have conditional expressions. @@ -1409,7 +1405,7 @@ conditional-expression = disjunctive-expression ":" conditional-expression ``` -Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression), [conditional-expression](#user-content-conditional-expression)_; +Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression)_; These are all the expressions. @@ -1442,7 +1438,7 @@ statement = expression-statement / block ``` -Go to: _[expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [console-statement](#user-content-console-statement), [loop-statement](#user-content-loop-statement), [conditional-statement](#user-content-conditional-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block), [variable-definition-statement](#user-content-variable-definition-statement)_; +Go to: _[expression-statement](#user-content-expression-statement), [variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [return-statement](#user-content-return-statement), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement)_; @@ -1485,7 +1481,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; @@ -1508,7 +1504,7 @@ Note that we require blocks in all branches, not merely statements. branch = "if" expression block ``` -Go to: _[expression](#user-content-expression), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [expression](#user-content-expression)_; @@ -1603,7 +1599,7 @@ Go to: _[formatted-string](#user-content-formatted-string)_; print-call = print-function print-arguments ``` -Go to: _[print-arguments](#user-content-print-arguments), [print-function](#user-content-print-function)_; +Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; An annotation consists of an annotation name (which starts with '@') @@ -1616,7 +1612,7 @@ annotation = annotation-name [ "(" identifier *( "," identifier ) ")" ] ``` -Go to: _[annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_; A function declaration defines a function. @@ -1636,7 +1632,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; +Go to: _[function-parameters](#user-content-function-parameters), [block](#user-content-block), [identifier](#user-content-identifier), [type](#user-content-type)_; @@ -1668,7 +1664,7 @@ Go to: _[function-input](#user-content-function-input)_; function-input = [ "const" ] identifier ":" type ``` -Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; @@ -1695,7 +1691,7 @@ Go to: _[member-function-declaration](#user-content-member-function-declaration) member-variable-declaration = identifier ":" type ``` -Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; @@ -1716,7 +1712,7 @@ circuit-declaration = *annotation "circuit" identifier "{" member-declaration *( "," member-declaration ) "}" ``` -Go to: _[identifier](#user-content-identifier), [member-declaration](#user-content-member-declaration)_; +Go to: _[member-declaration](#user-content-member-declaration), [identifier](#user-content-identifier)_; An import declaration consists of the 'import' keyword @@ -1745,7 +1741,7 @@ package-path = "*" / "(" package-path *( "," package-path ) [","] ")" ``` -Go to: _[package-path](#user-content-package-path), [identifier](#user-content-identifier), [package-name](#user-content-package-name)_; +Go to: _[package-path](#user-content-package-path), [package-name](#user-content-package-name), [identifier](#user-content-identifier)_; Finally, we define a file as a sequence of zero or more declarations. @@ -1763,7 +1759,7 @@ declaration = import-declaration / circuit-declaration ``` -Go to: _[function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration)_; +Go to: _[import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_; diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index d91c09a750..54212c89d1 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -1,8 +1,6 @@ ; Leo Library ; ; Copyright (C) 2021 Aleo Systems Inc. -; -; Author: Alessandro Coglio (acoglio on GitHub) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From bbc70d927b4d9a376f05490664b15bab0d3ea061 Mon Sep 17 00:00:00 2001 From: damirka Date: Tue, 6 Apr 2021 10:51:05 +0300 Subject: [PATCH 077/108] build -> compiling in log --- leo/commands/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 392859e238..303eb432b8 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -42,7 +42,7 @@ impl Command for Build { type Output = Option<(Compiler<'static, Fq, EdwardsGroupType>, bool)>; fn log_span(&self) -> Span { - tracing::span!(tracing::Level::INFO, "Build") + tracing::span!(tracing::Level::INFO, "Compiling") } fn prelude(&self, _: Context) -> Result { From 751b42ab5b0855b32bd69458e90534ac92c18937 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 6 Apr 2021 10:36:36 +0000 Subject: [PATCH 078/108] Bump abnf from 0.10.1 to 0.10.2 Bumps [abnf](https://github.com/duesee/abnf) from 0.10.1 to 0.10.2. - [Release notes](https://github.com/duesee/abnf/releases) - [Commits](https://github.com/duesee/abnf/commits) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 4 ++-- grammar/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fac6a616e0..f7c63fefa2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "abnf" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb23c378acfcb46052bd7d1a6119d8d608d4c12ac6c72cb1d9c4e85bc2cb2bb7" +checksum = "fd8863e7db43447ad50376e19b0549343b72ad45cbd394b3fc8fe3ede961facc" dependencies = [ "abnf-core", "nom 6.1.2", diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index 5360ec457c..2e4b90f68d 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -14,5 +14,5 @@ keywords = [ ] [dependencies] -abnf = "0.10.1" +abnf = "0.10.2" anyhow = "1.0" From 48635e5dbe29929c156bb7fb311b47866eb462e7 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 14:22:15 -0700 Subject: [PATCH 079/108] [ABNF] Fix typos in documentation. --- grammar/abnf-grammar.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 54212c89d1..a3f7dde1af 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -18,7 +18,7 @@ ; Note that this CR LF requirement only applies to the grammar files themselves. ; It does not apply to the lines of the languages described by the grammar. -; ABNF grammar may describe any kinds of languages, +; ABNF grammars may describe any kind of languages, ; with any kind of line terminators, ; or even without line terminators at all (e.g. for "binary" languages). From 742e3b33ea286b47fff83664934dd644ab78e8dc Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 14:26:27 -0700 Subject: [PATCH 080/108] [ABNF] Improve introduction section of documentation. Update to say that grammar is no longer just a draft. Put primary motivation and purpose of grammar first. Mention use in formalization second, and slightly simplify that part, given that the formalization is not public yet. --- grammar/abnf-grammar.txt | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index a3f7dde1af..9be6139765 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -27,29 +27,23 @@ ; Introduction ; ------------ -; This file contains an initial draft of -; a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. +; This file contains an ABNF (Augmented Backus-Naur Form) grammar of Leo. ; Background on ABNF is provided later in this file. -; The initial motivation for creating an ABNF grammar of Leo was that -; we have a formally verified parser of ABNF grammars +; This grammar provides an official definition of the syntax of Leo +; that is both human-readable and machine-readable. +; It will be part of an upcoming Leo language reference. +; It may also be used to generate parser tests at some point. + +; We are also using this grammar +; as part of a mathematical formalization of the Leo language, +; which we are developing in the ACL2 theorem prover +; and which we plan to publish at some point. +; In particular, we have used a formally verified parser of ABNF grammars ; (at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; ; also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) -; which we have used to parse this ABNF grammar of Leo -; into a formal representation, in the ACL2 theorem prover, -; of the Leo concrete syntax. -; The parsing of this grammar file into an ACL2 representation -; happens every time the ACL2 formalization of Leo is built. - -; In addition to that initial motivation, -; this ABNF grammar has now the additional and primary purpose of -; providing an official definition of the syntax of Leo -; that is both human-readable and machine-readable. -; This grammar will be part of the (upcoming) Leo language reference, -; of the Leo Language Formal Specification -; (i.e. the LaTeX document in the leo-semantics repo), -; and of the ACL2 formalization of Leo (which was the initial motivation). -; It has also been suggested that it may be used to generate tests. +; to parse this grammar into a formal representation of the Leo concrete syntax +; and to validate that the grammar satisfies certain consistency properties. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From c7fb2905c0b5ef5a7f9183099797b3f42abbfa29 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 14:45:23 -0700 Subject: [PATCH 081/108] [ABNF] Improve background section of documentation. Explicate references to RFCs a bit. Use the term 'sequence of terminals' instead of 'string' to avoid any confusion. (Still use 'string' to refer to the actual strings in double quotes that are part of the ABNF notation itself.) --- grammar/abnf-grammar.txt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 9be6139765..0cf2ec1e79 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -51,13 +51,10 @@ ; ------------------ ; ABNF is an Internet standard: -; see https://www.rfc-editor.org/info/rfc5234 -; and https://www.rfc-editor.org/info/rfc7405. +; see RFC 5234 at https://www.rfc-editor.org/info/rfc5234 +; and RFC 7405 at https://www.rfc-editor.org/info/rfc7405. ; It is used to specify the syntax of JSON, HTTP, and other standards. -; The following is copied (and "un-LaTeX'd") from the aforementioned paper -; (at https://www.kestrel.edu/people/coglio/vstte18.pdf). - ; ABNF adds conveniences and makes slight modifications ; to Backus-Naur Form (BNF), ; without going beyond context-free grammars. @@ -74,15 +71,15 @@ ; and denotes them via: ; (i) binary, decimal, or hexadecimal sequences, ; e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A -; all denote the string '1 3 10'; +; all denote the sequence of terminals '1 3 10'; ; (ii) binary, decimal, or hexadecimal ranges, -; e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 -; (an ASCII digit); +; e.g. %x30-39 denotes any singleton sequence of terminals +; 'n' with 48 <= n <= 57 (an ASCII digit); ; (iii) case-sensitive ASCII strings, -; e.g. %s"Ab" denotes the string '65 98'; +; e.g. %s"Ab" denotes the sequence of terminals '65 98'; ; and (iv) case-insensitive ASCII strings, ; e.g. %i"ab", or just "ab", denotes -; any string among +; any sequence of terminals among ; '65 66', ; '65 98', ; '97 66', and @@ -106,7 +103,7 @@ ; Repetition prefixes have precedence over juxtapositions, ; which have precedence over /. ; Round brackets group things and override the aforementioned precedence rules, -; e.g. *(WSP / CRLF WSP) denotes strings +; e.g. *(WSP / CRLF WSP) denotes sequences of terminals ; obtained by repeating, zero or more times, ; either (i) a WSP or (ii) a CRLF followed by a WSP. ; Square brackets also group things but make them optional, From 11c0d60021e1a28188c635418056c73aac5abc96 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 14:59:52 -0700 Subject: [PATCH 082/108] [ABNF] Improve structure section of documentation. Make this more concise and clear by just presenting the lexical and syntactic grammar as the way we define the Leo syntax, as opposed to discussing alternatives like PEGs. --- grammar/abnf-grammar.txt | 53 +++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 0cf2ec1e79..16071d1c29 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -130,49 +130,42 @@ ; Structure ; --------- -; Language specifications often define the syntax of their languages via +; This ABNF grammar consists of two (sub)grammars: ; (i) a lexical grammar that describes how ; sequence of characters are parsed into tokens, and ; (ii) a syntactic grammar that described how ; tokens are parsed into expressions, statements, etc. -; (The adjectives 'lexical' and 'syntactic' are -; the ones used in the Java language specification; -; other terms may be used by other languages, -; but the essence is similar.) -; The situation is sometimes more complex, -; with multiple passes (e.g. Unicode escape processing in Java), -; but the division between lexical and syntactic (in the sense above) stands. +; The adjectives 'lexical' and 'syntactic' are +; the same ones used in the Java language reference, +; for instance; +; alternative terms may be used in other languages, +; but the separation into these two components is quite common +; (the situation is sometimes a bit more complex, with multiple passes, +; e.g. Unicode escape processing in Java). -; In the aforementioned language specifications, -; both the lexical and syntactic grammars -; are normally written in a context-free grammar notation, -; augmented with natural language that may assert, for instance, -; that tokenization always takes the longest sequence that constitutes a token. - -; This dual structure appears to be motivated by the fact that +; This separation enables ; concerns of white space, line endings, etc. -; can be handled by the lexical grammar, -; allowing the syntactic grammar to focus on the more important structure. -; Handling both aspects in a single context-free grammar may be unwieldy, +; to be handled by the lexical grammar, +; with the syntactic grammar focused on the more important structure. +; Handling both aspects in a single grammar may be unwieldy, ; so having two grammars provides more clarity and readability. -; In contrast, PEG (Parsing Expression Grammar) formalisms like Pest -; naturally embody a procedural interpretation -; that can handle white space and tokenization in just one manageable grammar. -; However, this procedural interpretaion may be sometimes -; less clear and readable to humans than context-free rules. -; Indeed, context-free grammar are commonly used to documentat languages. - -; ABNF is a context-free grammar notation, -; with no procedural interpretation, -; and therefore it makes sense to define -; separate lexical and syntactic ABNF grammars for Leo. -; Conceptually, the two grammars define two subsequent processing phases, +; ABNF is a context-free grammar notation, with no procedural interpretation. +; The two grammars conceptually define two subsequent processing phases, ; as detailed below. ; However, a parser implementation does not need to perform ; two strictly separate phases (in fact, it typically does not), ; so long as it produces the same final result. +; The grammar is accompanied by some extra-grammatical requirements, +; which are not conveniently expressible in a context-free grammar like ABNF. +; These requirements are needed to make the grammar unambiguous, +; i.e. to ensure that, for each sequence of terminals, +; there is exactly one parse tree for that sequence terminals +; that satisfies not only the grammar rules +; but also the extra-grammatical requirements. +; These requirements are expressed as comments in this file. + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Operator Precedence From fdaab572f91b4b787e72aa045f014e81382e2671 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 15:14:08 -0700 Subject: [PATCH 083/108] [ABNF] Improve operator precedence section of documentation. Fix a typo. Tweak some text layout. --- grammar/abnf-grammar.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 16071d1c29..485cc19118 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -187,8 +187,9 @@ ; / additive-expression "+" multiplicative-expression ; / additive-expression "-" multiplicative-expression ; -; this rule tells us that the additive operators '+' and '-' have -; lower precedence than the multiplicative operators '*' and '/', +; These rules tell us +; that the additive operators '+' and '-' have lower precedence +; than the multiplicative operators '*' and '/', ; and that both the additive and multiplicative operators associate to the left. ; This may be best understood via the examples given below. From e035743f962610b145e0cd452530b7bcdcf70b3c Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 15:19:41 -0700 Subject: [PATCH 084/108] [ABNF] Improve naming convention section of documentation. Some tweaks and some clarifications. --- grammar/abnf-grammar.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 485cc19118..8f1f5876bd 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -244,14 +244,14 @@ ; Naming Convention ; ----------------- -; For this ABNF grammar, we choose nonterminal names +; This ABNF grammar uses nonterminal names ; that consist of complete English words, separated by dashes, ; and that describe the construct the way it is in English. ; For instance, we use the name 'conditional-statement' ; to describe conditional statements. -; At the same time, we attempt to establish -; a precise and "official" nomenclature for the Leo constructs, +; At the same time, this grammar establishes +; a precise and official nomenclature for the Leo constructs, ; by way of the nonterminal names that define their syntax. ; For instance, the rule ; @@ -269,19 +269,21 @@ ; is the fact that, as discussed above, ; we write the grammar rules in a way that determines ; the relative precedence and the associativity of expression operators, -; and that therefore we have rules like +; and therefore we have rules like ; ; unary-expression = primary-expression ; / "!" unary-expression ; / "-" unary-expression ; ; In order to allow the recursion of the rule to stop, -; we need to regard, in the grammar, a primary expression as a unary expression. +; we need to regard, in the grammar, a primary expression as a unary expression +; (i.e. a primary expression is also a unary expression in the grammar; +; but note that the opposite is not true). ; However, this is just a grammatical artifact: ; ontologically, a primary expression is not really a unary expression, ; because a unary expression is one that consists of ; a unary operator and an operand sub-expression. -; These terminological "exceptions" should be easy to identify in the rules. +; These terminological exceptions should be easy to identify in the rules. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From f0bac48093c6115b5929dfe856d02d0d4d0e95c3 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 16:03:28 -0700 Subject: [PATCH 085/108] [ABNF] Improve lexical grammar documentation. Fix some typos, clarify some text, remove/update some obsolete references. --- grammar/abnf-grammar.txt | 62 +++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 8f1f5876bd..99fef41eea 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -295,11 +295,12 @@ ; which are numbers in the range form 0 to 10FFFFh. ; These are captured by the ABNF rule 'character' below. -; The lexical grammar defines how, conceptually, +; The lexical grammar defines how, at least conceptually, ; the sequence of characters is turned into -; a sequence of tokens, comments, and whitespaces. +; a sequence of tokens, comments, and whitespaces: +; these entities are all defined by the grammar rules below. -; As stated, the lexical grammar is ambiguous. +; As stated, the lexical grammar alone is ambiguous. ; For example, the sequence of characters '**' (i.e. two stars) ; could be equally parsed as two '*' symbol tokens or one '**' symbol token ; (see rule for 'symbol' below). @@ -314,10 +315,6 @@ ; the longest possible sequence of characters is always parsed. ; This way, '**' must be parsed as one '**' symbol token, ; and '' must be parsed as one line terminator. -; (We should formalize this requirement, -; along with the other extra-grammatical requirements given below, -; and formally prove that they indeed make -; the lexical grammar of Leo unambiguous.) ; As mentioned above, a character is any Unicode code point. ; This grammar does not say how those are encoded in files (e.g. UTF-8): @@ -356,7 +353,8 @@ not-star-or-slash = %x0-29 / %x2B-2E / %x30-10FFFF ; anything but * or / ; a line feed, ; or a carriage return immediately followed by a line feed. ; Note that the latter combination constitutes a single line terminator, -; according to the extra-grammatical rule of the longest sequence. +; according to the extra-grammatical requirement of the longest sequence, +; described above. newline = line-feed / carriage-return / carriage-return line-feed @@ -366,13 +364,13 @@ whitespace = space / horizontal-tab / newline ; There are two kinds of comments in Leo, as in other languages. ; One is block comments of the form '/* ... */', -; and the other is end-of-line comments '// ...'. +; and the other is end-of-line comments of the form '// ...'. ; The first kind start at '/*' and end at the first '*/', ; possibly spanning multiple (partial) lines; -; they do no nest. +; these do no nest. ; The second kind start at '//' and extend till the end of the line. ; The rules about comments given below are similar to -; the ones used in the Java language specification. +; the ones used in the Java language reference. comment = block-comment / end-of-line-comment @@ -454,9 +452,9 @@ package-name = 1*( lowercase-letter / digit ) address = %s"aleo1" 58( lowercase-letter / digit ) -; A format string is a sequence of characters, other than double quote, +; A formatted string is a sequence of characters, other than double quote, ; surrounded by double quotes. -; Within a format string, substrings '{}' are distinguished as containers +; Within a formatted string, substrings '{}' are distinguished as containers ; (these are the ones that may be matched with values ; whose textual representation replaces the containers ; in the printed string). @@ -469,12 +467,12 @@ address = %s"aleo1" 58( lowercase-letter / digit ) formatted-string-container = "{}" formatted-string = double-quote - *( not-double-quote / formatted-string-container ) - double-quote + *( not-double-quote / formatted-string-container ) + double-quote ; Here is (part of this ABNF comment), -; an alternative way to specify format strings, -; which captures the extra-grammatical requirement above in the grammar +; an alternative way to specify formatted strings, +; which captures the extra-grammatical requirement above in the grammar, ; but is more complicated: ; ; not-double-quote-or-open-brace = %x0-22 / %x24-7A / %x7C-10FFFF @@ -482,27 +480,25 @@ formatted-string = double-quote ; not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF ; ; formatted-string-element = not-double-quote-or-open-brace -; / "{" not-double-quote-or-close-brace -; / formatted-string-container +; / "{" not-double-quote-or-close-brace +; / formatted-string-container ; ; formatted-string = double-quote *formatted-string-element double-quote ; ; It is not immediately clear which approach is better; there are tradeoffs. -; Regardless, we should choose one eventually. +; We may choose to adopt this one in future revisions of the grammar. -; Annotations are built out of names and arguments, which are tokens. -; Two names are currently supported. -; An argument is a sequence of one or more letters, digits, and underscores. +; Annotations have names, which are identifiers immediately preceded by '@'. annotation-name = "@" identifier ; A natural (number) is a sequence of one or more digits. -; Note that we allow leading zeros, e.g. '007'. +; We allow leading zeros, e.g. '007'. natural = 1*digit ; An integer (number) is either a natural or its negation. -; Note that we also allow leading zeros in negative numbers, e.g. '-007'. +; We allow leading zeros also in negative numbers, e.g. '-007'. integer = [ "-" ] natural @@ -539,7 +535,9 @@ boolean-literal = %s"true" / %s"false" address-literal = %s"address" "(" address ")" -; The ones above are all the literals, as defined by the following rule. +; The ones above are all the atomic literals +; (in the sense that they are tokens, without whitespace allowed in them), +; as defined by the following rule. atomic-literal = untyped-literal / unsigned-literal @@ -553,14 +551,14 @@ atomic-literal = untyped-literal ; it remains to define tokens for non-alphanumeric symbols such as "+" and "(". ; Different programming languages used different terminologies for these, ; e.g. operators, separators, punctuators, etc. -; Here we use 'symbol', for all of them, but we can do something different. +; Here we use 'symbol', for all of them. ; We also include a token consisting of ; a closing parenthesis immediately followed by 'group': ; as defined in the syntactic grammar, -; this is the final part of an affine group literal. -; Even though it includes letters, +; this is the final part of an affine group literal; +; even though it includes letters, ; it seems appropriate to still consider it a symbol, -; particularly since it starts with a symbol. +; particularly since it starts with a proper symbol. ; We could give names to all of these symbols, ; via rules such as @@ -955,8 +953,8 @@ assignment-statement = expression assignment-operator expression ";" ; The call may be an assertion or a print command. ; The former takes an expression (which must be boolean) as argument. ; The latter takes either no argument, -; or a format string followed by expressions, -; whose number must match the number of containers '{}' in the format string. +; or a formatted string followed by expressions, +; whose number must match the number of containers '{}' in the formatted string. ; Note that the console function names are identifiers, not keywords. ; There are three kind of printing. From 5f8530844439dc3b2a4adb0edd2f37c3b8b6625c Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 16:35:47 -0700 Subject: [PATCH 086/108] [ABNF] Improve the syntactic grammar section documentation. Update some comments that were now out of date. Clarify some text. Fix some typos. --- grammar/abnf-grammar.txt | 128 +++++++++++++++------------------------ 1 file changed, 50 insertions(+), 78 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 99fef41eea..86e6599266 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -641,7 +641,7 @@ scalar-type = boolean-type / arithmetic-type / address-type ; Circuit types are denoted by identifiers and the keyword 'Self'. ; The latter is only allowed inside a circuit definition, -; to denote the defined circuit. +; to denote the circuit being defined. self-type = %s"Self" @@ -653,9 +653,8 @@ tuple-type = "(" [ type 1*( "," type ) ] ")" ; An array type consists of an element type ; and an indication of dimensions. -; There is either a single dimension (a number), -; or a tuple of one or more dimensions -; (we could restrict the latter to two or more dimensions). +; There is either a single dimension, +; or a tuple of one or more dimensions. array-type = "[" type ";" array-dimensions "]" @@ -672,12 +671,12 @@ aggregate-type = tuple-type / array-type / circuit-type type = scalar-type / aggregate-type -; The lexical grammar above defines product group literals. +; The lexical grammar given earlier defines product group literals. ; The other kind of group literal is a pair of integer coordinates, ; which are reduced modulo the prime to identify a point, ; which must be on the elliptic curve. -; It is also allowed to omit one (not both) coordinates, -; with an indication of how to infer the missing coordinate +; It is also allowed to omit one coordinate (not both), +; with an indication of how to fill in the missing coordinate ; (i.e. sign high, sign low, or inferred). ; This is an affine group literal, ; because it consists of affine point coordinates. @@ -687,8 +686,6 @@ group-coordinate = integer / "+" / "-" / "_" affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" ; A literal is either an atomic one or an affine group literal. -; Here 'atomic' refers to being a token or not, -; since no whitespace is allowed within a token. literal = atomic-literal / affine-group-literal @@ -706,13 +703,12 @@ group-literal = product-group-literal / affine-group-literal ; and the (left or right) associativity of binary operators. ; The primary expressions are self-contained in a way, -; i.e. they have clear deliminations. -; Some consist of single tokens: -; identifiers, the keywords 'self' and 'input', and literals. +; i.e. they have clear deliminations: +; Some consist of single tokens, +; while others have explicit endings. ; Primary expressions also include parenthesized expressions, ; i.e. any expression may be turned into a primary one ; by putting parentheses around it. -; The other kinds are defined and explained below. primary-expression = identifier / %s"self" @@ -723,35 +719,19 @@ primary-expression = identifier / array-expression / circuit-expression -; There are tuple expressions to construct and deconstruct tuples. -; A construction consists of zero, two, or more component expressions. -; A deconstruction uses a component index (zero-indexed). -; Note that constructions are delimited by closing parentheses -; and deconstructions are delimited by natural tokens. -; The rule below, and similar rules for other aggregate types, -; use the perhaps more familiar 'access', -; but note that 'deconstruction' has a nice symmetry to 'construction'; -; the term 'destructor' has a different meaning in other languages, -; so we may want to avoid it, but not necessarily. +; Tuple expressions construct tuples. +; Each consists of zero, two, or more component expressions. tuple-construction = "(" [ expression 1*( "," expression ) ] ")" tuple-expression = tuple-construction -; The are array expressions to construct and deconstruct arrays. -; There are two kinds of constructions: +; Array expressions construct arrays. +; There are two kinds: ; one lists the element expressions (at least one), ; including spreads (via '...') which are arrays being spliced in; ; the other repeats (the value of) a single expression ; across one or more dimensions. -; There are two kinds of deconstructions: -; one selects a single element by index (zero-indexed); -; the other selects a range via two indices, -; the first inclusive and the second exclusive -- -; both are optional, -; the first defaulting to 0 and the second to the array length. -; Note that these expressions are all delimited -; by closing square brackets. array-inline-construction = "[" array-inline-element @@ -766,17 +746,14 @@ array-construction = array-inline-construction / array-repeat-construction array-expression = array-construction -; There are circuit expressions to construct and deconstruct circuit values. -; A construction lists values for all the member variables (in any order); -; there must be at least one member variable currently. +; Circuit expressions construct circuit values. +; Each lists values for all the member variables (in any order); +; there must be at least one member variable. ; A single identifier abbreviates -; a pair consisting of the same identifier separated by dot; +; a pair consisting of the same identifier separated by colon; ; note that, in the expansion, the left one denotes a member name, ; while the right one denotes an expression (a variable), ; so they are syntactically identical but semantically different. -; A deconstruction selects a member variable by name. -; Note that these expressions are delimited, -; by closing curly braces or identifiers. circuit-construction = circuit-type "{" circuit-inline-element *( "," circuit-inline-element ) @@ -786,20 +763,28 @@ circuit-inline-element = identifier ":" expression / identifier circuit-expression = circuit-construction +; After primary expressions, postfix expressions have highest precedence. +; They apply to primary expressions, and recursively to postfix expressions. + +; There are postfix expressions to access parts of aggregate values. +; A tuple access selects a component by index (zero-based). +; There are two kinds of array accesses: +; one selects a single element by index (zero-based); +; the other selects a range via two indices, +; the first inclusive and the second exclusive -- +; both are optional, +; the first defaulting to 0 and the second to the array length. +; A circuit access selects a member variable by name. + +; Function calls are also postfix expressions. ; There are three kinds of function calls: ; top-level function calls, ; instance (i.e. non-static) member function calls, and ; static member function calls. -; What changes is the start, but they all end in an argument list, -; delimited by a closing parenthesis. +; What changes is the start, but they all end in an argument list. function-arguments = "(" [ expression *( "," expression ) ] ")" -; Postfix expressions have highest precedence. -; They apply to primary expressions. -; Contains access expressions for arrays, tuples, and circuits. -; Contains function call types. - postfix-expression = primary-expression / postfix-expression "." natural / postfix-expression "." identifier @@ -810,7 +795,7 @@ postfix-expression = primary-expression / postfix-expression "[" [expression] ".." [expression] "]" ; Unary operators have the highest operator precedence. -; They apply to postfix expressions +; They apply to postfix expressions, ; and recursively to unary expressions. unary-expression = postfix-expression @@ -818,7 +803,7 @@ unary-expression = postfix-expression / "-" unary-expression ; Next in the operator precedence is casting. -; The current rule below makes exponentiation left-associative, + cast-expression = unary-expression / cast-expression %s"as" type @@ -826,7 +811,6 @@ cast-expression = unary-expression ; following mathematical practice. ; The current rule below makes exponentiation left-associative, ; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. -; This is easy to change if we want it to be right-associative instead. exponential-expression = cast-expression / exponential-expression "**" cast-expression @@ -852,8 +836,8 @@ ordering-expression = additive-expression / additive-expression "<=" additive-expression / additive-expression ">=" additive-expression -; Equalities return booleans but may also operate on boolean, -; so we make them left-associative. +; Equalities return booleans but may also operate on booleans; +; the rule below makes them left-associative. equality-expression = ordering-expression / equality-expression "==" ordering-expression @@ -872,11 +856,11 @@ disjunctive-expression = conjunctive-expression ; Finally we have conditional expressions. conditional-expression = disjunctive-expression - / conditional-expression + / conditional-expression "?" expression ":" conditional-expression -; These are all the expressions. +; Those above are all the expressions. ; Recall that conditional expressions ; may be disjunctive expressions, ; which may be conjunctive expressions, @@ -884,9 +868,8 @@ conditional-expression = disjunctive-expression expression = conditional-expression -; There are various kinds of statements, -; including blocks, which are -; possibly empty sequences of statements surounded by curly braces. +; There are various kinds of statements, including blocks. +; Blocks are possibly empty sequences of statements surrounded by curly braces. statement = expression-statement / return-statement @@ -899,13 +882,13 @@ statement = expression-statement block = "{" *statement "}" -; An expression (that returns the empty tuple) +; An expression (that must return the empty tuple, as semantically required) ; can be turned into a statement by appending a semicolon. expression-statement = expression ";" ; A return statement always takes an expression, -; and does not end with a semicolon (but we may want to change that). +; and does not end with a semicolon. return-statement = %s"return" expression @@ -926,7 +909,7 @@ identifier-or-identifiers = identifier ; (which together form a branch). ; It may stop there, or it may continue with an alternative block, ; or possibly with another conditional statement, forming a chain. -; Note that we require blocks in all branches, not merely statements. +; Note that blocks are required in all branches, not merely statements. branch = %s"if" expression block @@ -956,7 +939,7 @@ assignment-statement = expression assignment-operator expression ";" ; or a formatted string followed by expressions, ; whose number must match the number of containers '{}' in the formatted string. ; Note that the console function names are identifiers, not keywords. -; There are three kind of printing. +; There are three kinds of print commands. console-statement = %s"console" "." console-call @@ -972,19 +955,17 @@ print-arguments = "(" [ formatted-string *( "," expression ) ] ")" print-call = print-function print-arguments ; An annotation consists of an annotation name (which starts with '@') -; with optional annotation arguments. +; with optional annotation arguments, which are identifiers. ; Note that no parentheses are used if there are no arguments. annotation = annotation-name [ "(" identifier *( "," identifier ) ")" ] ; A function declaration defines a function. -; This could be called 'function-definition' instead, -; but see the comments about the 'declaration' rule below. -; The output type is optional (it defaults to the empty tuple type). +; The output type is optional, defaulting to the empty tuple type. ; In general, a function input consists of an identifier and a type, ; with an optional 'const' modifier. -; However, functions inside circuits +; Additionally, functions inside circuits ; may start with a 'mut self' or 'const self' or 'self' parameter. ; Furthermore, any function may end with an 'input' parameter. @@ -1007,8 +988,6 @@ input-parameter = %s"input" ; A circuit member variable declaration consists of an identifier and a type. ; A circuit member function declaration consists of a function declaration. -; We could call these 'member-definition' etc., -; but see the comments about the 'declaration' rule below. member-declaration = member-variable-declaration / member-function-declaration @@ -1017,9 +996,8 @@ member-variable-declaration = identifier ":" type member-function-declaration = function-declaration -; A circuit declaration defines a circuit type. It is straightforward. -; This could be called 'circuit-definition' instead, -; but see the comments about the 'declaration' rule below. +; A circuit declaration defines a circuit type, +; as consisting of member variables and functions. circuit-declaration = *annotation %s"circuit" identifier "{" member-declaration *( "," member-declaration ) "}" @@ -1032,7 +1010,7 @@ circuit-declaration = *annotation %s"circuit" identifier ; or a parenthesized list of package paths, ; which are "fan out" of the initial path. ; Note that we allow the last element of the parenthesized list -; to be followed by a comma, presumably for convenience. +; to be followed by a comma, for convenience. import-declaration = %s"import" package-path @@ -1042,12 +1020,6 @@ package-path = "*" / "(" package-path *( "," package-path ) [","] ")" ; Finally, we define a file as a sequence of zero or more declarations. -; This is why we used 'function-declaration' and 'circuit-declaration' -; instead of 'function-definition' and 'ciruit-definition': -; this way, they are all declarations of some sort. -; An import declaration cannot really called an import definition, -; because it does not define anything. -; But we may revisit this, and use 'definition' instead of 'declaration'. declaration = import-declaration / function-declaration From 7da8a3c033c03c4aeffb235f192f7239f48ef707 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 16:37:18 -0700 Subject: [PATCH 087/108] [ABNF] Improve consistency of documentation. --- grammar/abnf-grammar.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 86e6599266..3db7c253a0 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -130,7 +130,7 @@ ; Structure ; --------- -; This ABNF grammar consists of two (sub)grammars: +; This ABNF grammar consists of two (sub-)grammars: ; (i) a lexical grammar that describes how ; sequence of characters are parsed into tokens, and ; (ii) a syntactic grammar that described how @@ -454,7 +454,7 @@ address = %s"aleo1" 58( lowercase-letter / digit ) ; A formatted string is a sequence of characters, other than double quote, ; surrounded by double quotes. -; Within a formatted string, substrings '{}' are distinguished as containers +; Within a formatted string, sub-strings '{}' are distinguished as containers ; (these are the ones that may be matched with values ; whose textual representation replaces the containers ; in the printed string). @@ -631,7 +631,7 @@ group-type = %s"group" arithmetic-type = integer-type / field-type / group-type ; The arithmetic types, along with the boolean and address types, -; form the scalar types, i.e. the ones whose values do not contain (sub)values. +; form the scalar types, i.e. the ones whose values do not contain (sub-)values. boolean-type = %s"bool" @@ -662,7 +662,7 @@ array-dimensions = natural / "(" natural *( "," natural ) ")" ; Circuit, tuple, and array types form the aggregate types, -; i.e. types whose values contain (sub)values +; i.e. types whose values contain (sub-)values ; (with the corner-case exception of the empty tuple value). aggregate-type = tuple-type / array-type / circuit-type From f19af30f0e231eda45017beedc0eb74ce7123a68 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 16:39:07 -0700 Subject: [PATCH 088/108] [ABNF] Fix rule for affine group literals. This was affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" instead of affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" (note the different ending). This change should have been part of the PR for whitespace in group literals, but apparently I failed to do that, along with the other changes. This commit rectifies that omission. --- grammar/abnf-grammar.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index 3db7c253a0..cb6635d8a1 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -683,7 +683,7 @@ type = scalar-type / aggregate-type group-coordinate = integer / "+" / "-" / "_" -affine-group-literal = "(" group-coordinate "," group-coordinate ")" %s"group" +affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" ; A literal is either an atomic one or an affine group literal. From d7d15b1bc4f9cb1fed53b5b6f0aaa5f83b188335 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 6 Apr 2021 16:41:12 -0700 Subject: [PATCH 089/108] [ABNF] Regenerate markdown file. --- grammar/abnf-grammar.md | 387 ++++++++++++++++++---------------------- 1 file changed, 175 insertions(+), 212 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index 08439bf320..a96d83885f 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -22,7 +22,7 @@ but its lines will always be terminated by CR LF on any system. Note that this CR LF requirement only applies to the grammar files themselves. It does not apply to the lines of the languages described by the grammar. -ABNF grammar may describe any kinds of languages, +ABNF grammars may describe any kind of languages, with any kind of line terminators, or even without line terminators at all (e.g. for "binary" languages). @@ -33,29 +33,23 @@ or even without line terminators at all (e.g. for "binary" languages). Introduction ------------ -This file contains an initial draft of -a complete ABNF (Augmented Backus-Naur Form) grammar of Leo. +This file contains an ABNF (Augmented Backus-Naur Form) grammar of Leo. Background on ABNF is provided later in this file. -The initial motivation for creating an ABNF grammar of Leo was that -we have a formally verified parser of ABNF grammars +This grammar provides an official definition of the syntax of Leo +that is both human-readable and machine-readable. +It will be part of an upcoming Leo language reference. +It may also be used to generate parser tests at some point. + +We are also using this grammar +as part of a mathematical formalization of the Leo language, +which we are developing in the ACL2 theorem prover +and which we plan to publish at some point. +In particular, we have used a formally verified parser of ABNF grammars (at https://github.com/acl2/acl2/tree/master/books/kestrel/abnf; also see the paper at https://www.kestrel.edu/people/coglio/vstte18.pdf) -which we have used to parse this ABNF grammar of Leo -into a formal representation, in the ACL2 theorem prover, -of the Leo concrete syntax. -The parsing of this grammar file into an ACL2 representation -happens every time the ACL2 formalization of Leo is built. - -In addition to that initial motivation, -this ABNF grammar has now the additional and primary purpose of -providing an official definition of the syntax of Leo -that is both human-readable and machine-readable. -This grammar will be part of the (upcoming) Leo language reference, -of the Leo Language Formal Specification -(i.e. the LaTeX document in the leo-semantics repo), -and of the ACL2 formalization of Leo (which was the initial motivation). -It has also been suggested that it may be used to generate tests. +to parse this grammar into a formal representation of the Leo concrete syntax +and to validate that the grammar satisfies certain consistency properties. -------- @@ -65,13 +59,10 @@ Background on ABNF ------------------ ABNF is an Internet standard: -see https://www.rfc-editor.org/info/rfc5234 -and https://www.rfc-editor.org/info/rfc7405. +see RFC 5234 at https://www.rfc-editor.org/info/rfc5234 +and RFC 7405 at https://www.rfc-editor.org/info/rfc7405. It is used to specify the syntax of JSON, HTTP, and other standards. -The following is copied (and "un-LaTeX'd") from the aforementioned paper -(at https://www.kestrel.edu/people/coglio/vstte18.pdf). - ABNF adds conveniences and makes slight modifications to Backus-Naur Form (BNF), without going beyond context-free grammars. @@ -88,15 +79,15 @@ ABNF uses only natural numbers as terminals, and denotes them via: (i) binary, decimal, or hexadecimal sequences, e.g. %b1.11.1010, %d1.3.10, and %x.1.3.A -all denote the string '1 3 10'; +all denote the sequence of terminals '1 3 10'; (ii) binary, decimal, or hexadecimal ranges, -e.g. %x30-39 denotes any string 'n' with 48 <= n <= 57 -(an ASCII digit); +e.g. %x30-39 denotes any singleton sequence of terminals +'n' with 48 <= n <= 57 (an ASCII digit); (iii) case-sensitive ASCII strings, -e.g. "Ab" denotes the string '65 98'; +e.g. "Ab" denotes the sequence of terminals '65 98'; and (iv) case-insensitive ASCII strings, e.g. %i"ab", or just "ab", denotes -any string among +any sequence of terminals among '65 66', '65 98', '97 66', and @@ -120,7 +111,7 @@ Instead of BNF's |, ABNF uses / to separate alternatives. Repetition prefixes have precedence over juxtapositions, which have precedence over /. Round brackets group things and override the aforementioned precedence rules, -e.g. *(WSP / CRLF WSP) denotes strings +e.g. *(WSP / CRLF WSP) denotes sequences of terminals obtained by repeating, zero or more times, either (i) a WSP or (ii) a CRLF followed by a WSP. Square brackets also group things but make them optional, @@ -149,49 +140,42 @@ and comments (semicolons to line endings). Structure --------- -Language specifications often define the syntax of their languages via +This ABNF grammar consists of two (sub-)grammars: (i) a lexical grammar that describes how sequence of characters are parsed into tokens, and (ii) a syntactic grammar that described how tokens are parsed into expressions, statements, etc. -(The adjectives 'lexical' and 'syntactic' are -the ones used in the Java language specification; -other terms may be used by other languages, -but the essence is similar.) -The situation is sometimes more complex, -with multiple passes (e.g. Unicode escape processing in Java), -but the division between lexical and syntactic (in the sense above) stands. +The adjectives 'lexical' and 'syntactic' are +the same ones used in the Java language reference, +for instance; +alternative terms may be used in other languages, +but the separation into these two components is quite common +(the situation is sometimes a bit more complex, with multiple passes, +e.g. Unicode escape processing in Java). -In the aforementioned language specifications, -both the lexical and syntactic grammars -are normally written in a context-free grammar notation, -augmented with natural language that may assert, for instance, -that tokenization always takes the longest sequence that constitutes a token. - -This dual structure appears to be motivated by the fact that +This separation enables concerns of white space, line endings, etc. -can be handled by the lexical grammar, -allowing the syntactic grammar to focus on the more important structure. -Handling both aspects in a single context-free grammar may be unwieldy, +to be handled by the lexical grammar, +with the syntactic grammar focused on the more important structure. +Handling both aspects in a single grammar may be unwieldy, so having two grammars provides more clarity and readability. -In contrast, PEG (Parsing Expression Grammar) formalisms like Pest -naturally embody a procedural interpretation -that can handle white space and tokenization in just one manageable grammar. -However, this procedural interpretaion may be sometimes -less clear and readable to humans than context-free rules. -Indeed, context-free grammar are commonly used to documentat languages. - -ABNF is a context-free grammar notation, -with no procedural interpretation, -and therefore it makes sense to define -separate lexical and syntactic ABNF grammars for Leo. -Conceptually, the two grammars define two subsequent processing phases, +ABNF is a context-free grammar notation, with no procedural interpretation. +The two grammars conceptually define two subsequent processing phases, as detailed below. However, a parser implementation does not need to perform two strictly separate phases (in fact, it typically does not), so long as it produces the same final result. +The grammar is accompanied by some extra-grammatical requirements, +which are not conveniently expressible in a context-free grammar like ABNF. +These requirements are needed to make the grammar unambiguous, +i.e. to ensure that, for each sequence of terminals, +there is exactly one parse tree for that sequence terminals +that satisfies not only the grammar rules +but also the extra-grammatical requirements. +These requirements are expressed as comments in this file. + -------- @@ -225,8 +209,9 @@ additive-expression = -this rule tells us that the additive operators '+' and '-' have -lower precedence than the multiplicative operators '*' and '/', +These rules tell us +that the additive operators '+' and '-' have lower precedence +than the multiplicative operators '*' and '/', and that both the additive and multiplicative operators associate to the left. This may be best understood via the examples given below. @@ -319,14 +304,14 @@ as second sub-expression, as it would in the second tree above. Naming Convention ----------------- -For this ABNF grammar, we choose nonterminal names +This ABNF grammar uses nonterminal names that consist of complete English words, separated by dashes, and that describe the construct the way it is in English. For instance, we use the name 'conditional-statement' to describe conditional statements. -At the same time, we attempt to establish -a precise and "official" nomenclature for the Leo constructs, +At the same time, this grammar establishes +a precise and official nomenclature for the Leo constructs, by way of the nonterminal names that define their syntax. For instance, the rule @@ -350,7 +335,7 @@ The only exception to the nomenclature-establishing role of the grammar is the fact that, as discussed above, we write the grammar rules in a way that determines the relative precedence and the associativity of expression operators, -and that therefore we have rules like +and therefore we have rules like @@ -363,12 +348,14 @@ unary-expression = primary-expression In order to allow the recursion of the rule to stop, -we need to regard, in the grammar, a primary expression as a unary expression. +we need to regard, in the grammar, a primary expression as a unary expression +(i.e. a primary expression is also a unary expression in the grammar; +but note that the opposite is not true). However, this is just a grammatical artifact: ontologically, a primary expression is not really a unary expression, because a unary expression is one that consists of a unary operator and an operand sub-expression. -These terminological "exceptions" should be easy to identify in the rules. +These terminological exceptions should be easy to identify in the rules. -------- @@ -382,11 +369,12 @@ represented as Unicode code points, which are numbers in the range form 0 to 10FFFFh. These are captured by the ABNF rule 'character' below. -The lexical grammar defines how, conceptually, +The lexical grammar defines how, at least conceptually, the sequence of characters is turned into -a sequence of tokens, comments, and whitespaces. +a sequence of tokens, comments, and whitespaces: +these entities are all defined by the grammar rules below. -As stated, the lexical grammar is ambiguous. +As stated, the lexical grammar alone is ambiguous. For example, the sequence of characters '**' (i.e. two stars) could be equally parsed as two '*' symbol tokens or one '**' symbol token (see rule for 'symbol' below). @@ -401,10 +389,6 @@ the extra-grammatical requirement that the longest possible sequence of characters is always parsed. This way, '**' must be parsed as one '**' symbol token, and '' must be parsed as one line terminator. -(We should formalize this requirement, -along with the other extra-grammatical requirements given below, -and formally prove that they indeed make -the lexical grammar of Leo unambiguous.) As mentioned above, a character is any Unicode code point. This grammar does not say how those are encoded in files (e.g. UTF-8): @@ -473,14 +457,15 @@ a single carriage return, a line feed, or a carriage return immediately followed by a line feed. Note that the latter combination constitutes a single line terminator, -according to the extra-grammatical rule of the longest sequence. +according to the extra-grammatical requirement of the longest sequence, +described above. ```abnf newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; +Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -490,18 +475,18 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[space](#user-content-space), [newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab)_; +Go to: _[newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space)_; There are two kinds of comments in Leo, as in other languages. One is block comments of the form '/* ... */', -and the other is end-of-line comments '// ...'. +and the other is end-of-line comments of the form '// ...'. The first kind start at '/*' and end at the first '*/', possibly spanning multiple (partial) lines; -they do no nest. +these do no nest. The second kind start at '//' and extend till the end of the line. The rules about comments given below are similar to -the ones used in the Java language specification. +the ones used in the Java language reference. ```abnf @@ -525,7 +510,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star / not-star rest-of-block-comment ``` -Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star)_; +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [not-star](#user-content-not-star), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; @@ -643,9 +628,9 @@ Thus an address always consists of 63 characters. address = "aleo1" 58( lowercase-letter / digit ) ``` -A format string is a sequence of characters, other than double quote, +A formatted string is a sequence of characters, other than double quote, surrounded by double quotes. -Within a format string, substrings '{}' are distinguished as containers +Within a formatted string, sub-strings '{}' are distinguished as containers (these are the ones that may be matched with values whose textual representation replaces the containers in the printed string). @@ -663,16 +648,16 @@ formatted-string-container = "{}" ```abnf formatted-string = double-quote - *( not-double-quote / formatted-string-container ) - double-quote + *( not-double-quote / formatted-string-container ) + double-quote ``` Go to: _[double-quote](#user-content-double-quote)_; Here is (part of this ABNF comment), -an alternative way to specify format strings, -which captures the extra-grammatical requirement above in the grammar +an alternative way to specify formatted strings, +which captures the extra-grammatical requirement above in the grammar, but is more complicated: @@ -691,8 +676,8 @@ not-double-quote-or-close-brace = %x0-22 / %x24-7C / %x7E-10FFFF ``` formatted-string-element = not-double-quote-or-open-brace - / "{" not-double-quote-or-close-brace - / formatted-string-container + / "{" not-double-quote-or-close-brace + / formatted-string-container ``` @@ -704,11 +689,9 @@ formatted-string = double-quote *formatted-string-element double-quote It is not immediately clear which approach is better; there are tradeoffs. -Regardless, we should choose one eventually. +We may choose to adopt this one in future revisions of the grammar. -Annotations are built out of names and arguments, which are tokens. -Two names are currently supported. -An argument is a sequence of one or more letters, digits, and underscores. +Annotations have names, which are identifiers immediately preceded by '@'. ```abnf @@ -719,7 +702,7 @@ Go to: _[identifier](#user-content-identifier)_; A natural (number) is a sequence of one or more digits. -Note that we allow leading zeros, e.g. '007'. +We allow leading zeros, e.g. '007'. ```abnf @@ -727,7 +710,7 @@ natural = 1*digit ``` An integer (number) is either a natural or its negation. -Note that we also allow leading zeros in negative numbers, e.g. '-007'. +We allow leading zeros also in negative numbers, e.g. '-007'. ```abnf @@ -809,7 +792,9 @@ address-literal = "address" "(" address ")" Go to: _[address](#user-content-address)_; -The ones above are all the literals, as defined by the following rule. +The ones above are all the atomic literals +(in the sense that they are tokens, without whitespace allowed in them), +as defined by the following rule. ```abnf @@ -822,21 +807,21 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[address-literal](#user-content-address-literal), [untyped-literal](#user-content-untyped-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [unsigned-literal](#user-content-unsigned-literal), [product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal)_; +Go to: _[product-group-literal](#user-content-product-group-literal), [unsigned-literal](#user-content-unsigned-literal), [address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [signed-literal](#user-content-signed-literal), [field-literal](#user-content-field-literal)_; After defining the (mostly) alphanumeric tokens above, it remains to define tokens for non-alphanumeric symbols such as "+" and "(". Different programming languages used different terminologies for these, e.g. operators, separators, punctuators, etc. -Here we use 'symbol', for all of them, but we can do something different. +Here we use 'symbol', for all of them. We also include a token consisting of a closing parenthesis immediately followed by 'group': as defined in the syntactic grammar, -this is the final part of an affine group literal. -Even though it includes letters, +this is the final part of an affine group literal; +even though it includes letters, it seems appropriate to still consider it a symbol, -particularly since it starts with a symbol. +particularly since it starts with a proper symbol. We could give names to all of these symbols, via rules such as @@ -895,7 +880,7 @@ token = keyword / symbol ``` -Go to: _[identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [formatted-string](#user-content-formatted-string), [annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal), [symbol](#user-content-symbol)_; +Go to: _[formatted-string](#user-content-formatted-string), [atomic-literal](#user-content-atomic-literal), [identifier](#user-content-identifier), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name)_; @@ -952,11 +937,11 @@ group-type = "group" arithmetic-type = integer-type / field-type / group-type ``` -Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_; +Go to: _[integer-type](#user-content-integer-type), [field-type](#user-content-field-type), [group-type](#user-content-group-type)_; The arithmetic types, along with the boolean and address types, -form the scalar types, i.e. the ones whose values do not contain (sub)values. +form the scalar types, i.e. the ones whose values do not contain (sub-)values. ```abnf @@ -973,12 +958,12 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type)_; +Go to: _[address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. The latter is only allowed inside a circuit definition, -to denote the defined circuit. +to denote the circuit being defined. ```abnf @@ -990,7 +975,7 @@ self-type = "Self" circuit-type = identifier / self-type ``` -Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; +Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; A tuple type consists of zero, two, or more component types. @@ -1005,16 +990,15 @@ Go to: _[type](#user-content-type)_; An array type consists of an element type and an indication of dimensions. -There is either a single dimension (a number), -or a tuple of one or more dimensions -(we could restrict the latter to two or more dimensions). +There is either a single dimension, +or a tuple of one or more dimensions. ```abnf array-type = "[" type ";" array-dimensions "]" ``` -Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_; +Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_; @@ -1027,7 +1011,7 @@ Go to: _[natural](#user-content-natural)_; Circuit, tuple, and array types form the aggregate types, -i.e. types whose values contain (sub)values +i.e. types whose values contain (sub-)values (with the corner-case exception of the empty tuple value). @@ -1035,7 +1019,7 @@ i.e. types whose values contain (sub)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type), [array-type](#user-content-array-type)_; +Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_; Scalar and aggregate types form all the types. @@ -1045,15 +1029,15 @@ Scalar and aggregate types form all the types. type = scalar-type / aggregate-type ``` -Go to: _[aggregate-type](#user-content-aggregate-type), [scalar-type](#user-content-scalar-type)_; +Go to: _[scalar-type](#user-content-scalar-type), [aggregate-type](#user-content-aggregate-type)_; -The lexical grammar above defines product group literals. +The lexical grammar given earlier defines product group literals. The other kind of group literal is a pair of integer coordinates, which are reduced modulo the prime to identify a point, which must be on the elliptic curve. -It is also allowed to omit one (not both) coordinates, -with an indication of how to infer the missing coordinate +It is also allowed to omit one coordinate (not both), +with an indication of how to fill in the missing coordinate (i.e. sign high, sign low, or inferred). This is an affine group literal, because it consists of affine point coordinates. @@ -1068,22 +1052,20 @@ Go to: _[integer](#user-content-integer)_; ```abnf -affine-group-literal = "(" group-coordinate "," group-coordinate ")" "group" +affine-group-literal = "(" group-coordinate "," group-coordinate ")group" ``` Go to: _[group-coordinate](#user-content-group-coordinate)_; A literal is either an atomic one or an affine group literal. -Here 'atomic' refers to being a token or not, -since no whitespace is allowed within a token. ```abnf literal = atomic-literal / affine-group-literal ``` -Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_; +Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_; The following rule is not directly referenced in the rules for expressions @@ -1106,13 +1088,12 @@ of operators and other expression constructs, and the (left or right) associativity of binary operators. The primary expressions are self-contained in a way, -i.e. they have clear deliminations. -Some consist of single tokens: -identifiers, the keywords 'self' and 'input', and literals. +i.e. they have clear deliminations: +Some consist of single tokens, +while others have explicit endings. Primary expressions also include parenthesized expressions, i.e. any expression may be turned into a primary one by putting parentheses around it. -The other kinds are defined and explained below. ```abnf @@ -1126,19 +1107,11 @@ primary-expression = identifier / circuit-expression ``` -Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [array-expression](#user-content-array-expression), [identifier](#user-content-identifier), [circuit-expression](#user-content-circuit-expression), [tuple-expression](#user-content-tuple-expression), [literal](#user-content-literal)_; -There are tuple expressions to construct and deconstruct tuples. -A construction consists of zero, two, or more component expressions. -A deconstruction uses a component index (zero-indexed). -Note that constructions are delimited by closing parentheses -and deconstructions are delimited by natural tokens. -The rule below, and similar rules for other aggregate types, -use the perhaps more familiar 'access', -but note that 'deconstruction' has a nice symmetry to 'construction'; -the term 'destructor' has a different meaning in other languages, -so we may want to avoid it, but not necessarily. +Tuple expressions construct tuples. +Each consists of zero, two, or more component expressions. ```abnf @@ -1156,20 +1129,12 @@ tuple-expression = tuple-construction Go to: _[tuple-construction](#user-content-tuple-construction)_; -The are array expressions to construct and deconstruct arrays. -There are two kinds of constructions: +Array expressions construct arrays. +There are two kinds: one lists the element expressions (at least one), including spreads (via '...') which are arrays being spliced in; the other repeats (the value of) a single expression across one or more dimensions. -There are two kinds of deconstructions: -one selects a single element by index (zero-indexed); -the other selects a range via two indices, -the first inclusive and the second exclusive -- -both are optional, -the first defaulting to 0 and the second to the array length. -Note that these expressions are all delimited -by closing square brackets. ```abnf @@ -1214,17 +1179,14 @@ array-expression = array-construction Go to: _[array-construction](#user-content-array-construction)_; -There are circuit expressions to construct and deconstruct circuit values. -A construction lists values for all the member variables (in any order); -there must be at least one member variable currently. +Circuit expressions construct circuit values. +Each lists values for all the member variables (in any order); +there must be at least one member variable. A single identifier abbreviates -a pair consisting of the same identifier separated by dot; +a pair consisting of the same identifier separated by colon; note that, in the expansion, the left one denotes a member name, while the right one denotes an expression (a variable), so they are syntactically identical but semantically different. -A deconstruction selects a member variable by name. -Note that these expressions are delimited, -by closing curly braces or identifiers. ```abnf @@ -1233,7 +1195,7 @@ circuit-construction = circuit-type "{" "}" ``` -Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; +Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_; @@ -1252,12 +1214,25 @@ circuit-expression = circuit-construction Go to: _[circuit-construction](#user-content-circuit-construction)_; +After primary expressions, postfix expressions have highest precedence. +They apply to primary expressions, and recursively to postfix expressions. + +There are postfix expressions to access parts of aggregate values. +A tuple access selects a component by index (zero-based). +There are two kinds of array accesses: +one selects a single element by index (zero-based); +the other selects a range via two indices, +the first inclusive and the second exclusive -- +both are optional, +the first defaulting to 0 and the second to the array length. +A circuit access selects a member variable by name. + +Function calls are also postfix expressions. There are three kinds of function calls: top-level function calls, instance (i.e. non-static) member function calls, and static member function calls. -What changes is the start, but they all end in an argument list, -delimited by a closing parenthesis. +What changes is the start, but they all end in an argument list. ```abnf @@ -1267,11 +1242,6 @@ function-arguments = "(" [ expression *( "," expression ) ] ")" Go to: _[expression](#user-content-expression)_; -Postfix expressions have highest precedence. -They apply to primary expressions. -Contains access expressions for arrays, tuples, and circuits. -Contains function call types. - ```abnf postfix-expression = primary-expression @@ -1284,11 +1254,11 @@ postfix-expression = primary-expression / postfix-expression "[" [expression] ".." [expression] "]" ``` -Go to: _[postfix-expression](#user-content-postfix-expression), [natural](#user-content-natural), [primary-expression](#user-content-primary-expression), [function-arguments](#user-content-function-arguments), [circuit-type](#user-content-circuit-type), [identifier](#user-content-identifier), [expression](#user-content-expression)_; +Go to: _[postfix-expression](#user-content-postfix-expression), [function-arguments](#user-content-function-arguments), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [natural](#user-content-natural), [expression](#user-content-expression)_; Unary operators have the highest operator precedence. -They apply to postfix expressions +They apply to postfix expressions, and recursively to unary expressions. @@ -1302,15 +1272,20 @@ Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expressio Next in the operator precedence is casting. -The current rule below makes exponentiation left-associative, + + +```abnf cast-expression = unary-expression / cast-expression "as" type +``` + +Go to: _[cast-expression](#user-content-cast-expression), [type](#user-content-type), [unary-expression](#user-content-unary-expression)_; + Next in the operator precedence is exponentiation, following mathematical practice. The current rule below makes exponentiation left-associative, i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'. -This is easy to change if we want it to be right-associative instead. ```abnf @@ -1318,7 +1293,7 @@ exponential-expression = cast-expression / exponential-expression "**" cast-expression ``` -Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_; +Go to: _[exponential-expression](#user-content-exponential-expression), [cast-expression](#user-content-cast-expression)_; Next in precedence come multiplication and division, both left-associative. @@ -1342,7 +1317,7 @@ additive-expression = multiplicative-expression / additive-expression "-" multiplicative-expression ``` -Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; +Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; Next in the precedence order are ordering relations. @@ -1360,8 +1335,8 @@ ordering-expression = additive-expression Go to: _[additive-expression](#user-content-additive-expression)_; -Equalities return booleans but may also operate on boolean, -so we make them left-associative. +Equalities return booleans but may also operate on booleans; +the rule below makes them left-associative. ```abnf @@ -1370,7 +1345,7 @@ equality-expression = ordering-expression / equality-expression "!=" ordering-expression ``` -Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_; +Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; Next come conjunctive expressions, left-associative. @@ -1400,7 +1375,7 @@ Finally we have conditional expressions. ```abnf conditional-expression = disjunctive-expression - / conditional-expression + / conditional-expression "?" expression ":" conditional-expression ``` @@ -1408,7 +1383,7 @@ conditional-expression = disjunctive-expression Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression)_; -These are all the expressions. +Those above are all the expressions. Recall that conditional expressions may be disjunctive expressions, which may be conjunctive expressions, @@ -1422,9 +1397,8 @@ expression = conditional-expression Go to: _[conditional-expression](#user-content-conditional-expression)_; -There are various kinds of statements, -including blocks, which are -possibly empty sequences of statements surounded by curly braces. +There are various kinds of statements, including blocks. +Blocks are possibly empty sequences of statements surrounded by curly braces. ```abnf @@ -1438,7 +1412,7 @@ statement = expression-statement / block ``` -Go to: _[expression-statement](#user-content-expression-statement), [variable-definition-statement](#user-content-variable-definition-statement), [loop-statement](#user-content-loop-statement), [return-statement](#user-content-return-statement), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block), [assignment-statement](#user-content-assignment-statement), [console-statement](#user-content-console-statement)_; +Go to: _[conditional-statement](#user-content-conditional-statement), [loop-statement](#user-content-loop-statement), [variable-definition-statement](#user-content-variable-definition-statement), [assignment-statement](#user-content-assignment-statement), [expression-statement](#user-content-expression-statement), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [block](#user-content-block)_; @@ -1446,7 +1420,7 @@ Go to: _[expression-statement](#user-content-expression-statement), [variable-de block = "{" *statement "}" ``` -An expression (that returns the empty tuple) +An expression (that must return the empty tuple, as semantically required) can be turned into a statement by appending a semicolon. @@ -1458,7 +1432,7 @@ Go to: _[expression](#user-content-expression)_; A return statement always takes an expression, -and does not end with a semicolon (but we may want to change that). +and does not end with a semicolon. ```abnf @@ -1481,7 +1455,7 @@ variable-definition-statement = ( "let" / "const" ) [ ":" type ] "=" expression ";" ``` -Go to: _[expression](#user-content-expression), [type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; +Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; @@ -1497,14 +1471,14 @@ A conditional statement always starts with a condition and a block (which together form a branch). It may stop there, or it may continue with an alternative block, or possibly with another conditional statement, forming a chain. -Note that we require blocks in all branches, not merely statements. +Note that blocks are required in all branches, not merely statements. ```abnf branch = "if" expression block ``` -Go to: _[block](#user-content-block), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [block](#user-content-block)_; @@ -1526,7 +1500,7 @@ The body is a block. loop-statement = "for" identifier "in" expression ".." expression block ``` -Go to: _[identifier](#user-content-identifier), [expression](#user-content-expression), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [expression](#user-content-expression)_; An assignment statement is straightforward. @@ -1543,7 +1517,7 @@ assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**=" assignment-statement = expression assignment-operator expression ";" ``` -Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [assignment-operator](#user-content-assignment-operator)_; Console statements start with the 'console' keyword, @@ -1551,10 +1525,10 @@ followed by a console function call. The call may be an assertion or a print command. The former takes an expression (which must be boolean) as argument. The latter takes either no argument, -or a format string followed by expressions, -whose number must match the number of containers '{}' in the format string. +or a formatted string followed by expressions, +whose number must match the number of containers '{}' in the formatted string. Note that the console function names are identifiers, not keywords. -There are three kind of printing. +There are three kinds of print commands. ```abnf @@ -1570,7 +1544,7 @@ console-call = assert-call / print-call ``` -Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_; +Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_; @@ -1603,7 +1577,7 @@ Go to: _[print-function](#user-content-print-function), [print-arguments](#user- An annotation consists of an annotation name (which starts with '@') -with optional annotation arguments. +with optional annotation arguments, which are identifiers. Note that no parentheses are used if there are no arguments. @@ -1612,16 +1586,14 @@ annotation = annotation-name [ "(" identifier *( "," identifier ) ")" ] ``` -Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_; +Go to: _[annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier)_; A function declaration defines a function. -This could be called 'function-definition' instead, -but see the comments about the 'declaration' rule below. -The output type is optional (it defaults to the empty tuple type). +The output type is optional, defaulting to the empty tuple type. In general, a function input consists of an identifier and a type, with an optional 'const' modifier. -However, functions inside circuits +Additionally, functions inside circuits may start with a 'mut self' or 'const self' or 'self' parameter. Furthermore, any function may end with an 'input' parameter. @@ -1632,7 +1604,7 @@ function-declaration = *annotation "function" identifier block ``` -Go to: _[function-parameters](#user-content-function-parameters), [block](#user-content-block), [identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; @@ -1643,7 +1615,7 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[input-parameter](#user-content-input-parameter), [self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs)_; +Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter)_; @@ -1674,8 +1646,6 @@ input-parameter = "input" A circuit member variable declaration consists of an identifier and a type. A circuit member function declaration consists of a function declaration. -We could call these 'member-definition' etc., -but see the comments about the 'declaration' rule below. ```abnf @@ -1683,7 +1653,7 @@ member-declaration = member-variable-declaration / member-function-declaration ``` -Go to: _[member-function-declaration](#user-content-member-function-declaration), [member-variable-declaration](#user-content-member-variable-declaration)_; +Go to: _[member-variable-declaration](#user-content-member-variable-declaration), [member-function-declaration](#user-content-member-function-declaration)_; @@ -1702,9 +1672,8 @@ member-function-declaration = function-declaration Go to: _[function-declaration](#user-content-function-declaration)_; -A circuit declaration defines a circuit type. It is straightforward. -This could be called 'circuit-definition' instead, -but see the comments about the 'declaration' rule below. +A circuit declaration defines a circuit type, +as consisting of member variables and functions. ```abnf @@ -1712,7 +1681,7 @@ circuit-declaration = *annotation "circuit" identifier "{" member-declaration *( "," member-declaration ) "}" ``` -Go to: _[member-declaration](#user-content-member-declaration), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [member-declaration](#user-content-member-declaration)_; An import declaration consists of the 'import' keyword @@ -1723,7 +1692,7 @@ a package name followed by a path, recursively; or a parenthesized list of package paths, which are "fan out" of the initial path. Note that we allow the last element of the parenthesized list -to be followed by a comma, presumably for convenience. +to be followed by a comma, for convenience. ```abnf @@ -1741,16 +1710,10 @@ package-path = "*" / "(" package-path *( "," package-path ) [","] ")" ``` -Go to: _[package-path](#user-content-package-path), [package-name](#user-content-package-name), [identifier](#user-content-identifier)_; +Go to: _[package-name](#user-content-package-name), [identifier](#user-content-identifier), [package-path](#user-content-package-path)_; Finally, we define a file as a sequence of zero or more declarations. -This is why we used 'function-declaration' and 'circuit-declaration' -instead of 'function-definition' and 'ciruit-definition': -this way, they are all declarations of some sort. -An import declaration cannot really called an import definition, -because it does not define anything. -But we may revisit this, and use 'definition' instead of 'declaration'. ```abnf From 74f02411e843ff70ea293dc7b953823a43187581 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Mon, 22 Mar 2021 14:25:50 +0100 Subject: [PATCH 090/108] fix: align with snarkVM's Integer changes Signed-off-by: ljedrz --- compiler/src/errors/value/integer.rs | 11 +++- compiler/src/statement/iteration/iteration.rs | 1 + compiler/src/value/address/address.rs | 4 +- compiler/src/value/integer/integer.rs | 4 +- compiler/src/value/integer/macros.rs | 58 ++++--------------- 5 files changed, 27 insertions(+), 51 deletions(-) diff --git a/compiler/src/errors/value/integer.rs b/compiler/src/errors/value/integer.rs index 457575b1dc..10a9f80bef 100644 --- a/compiler/src/errors/value/integer.rs +++ b/compiler/src/errors/value/integer.rs @@ -16,7 +16,7 @@ use leo_ast::{FormattedError, LeoError, Span}; -use snarkvm_gadgets::errors::SignedIntegerError; +use snarkvm_gadgets::errors::{SignedIntegerError, UnsignedIntegerError}; use snarkvm_r1cs::SynthesisError; #[derive(Debug, Error)] @@ -38,6 +38,15 @@ impl IntegerError { Self::new_from_span(message, span) } + pub fn unsigned(error: UnsignedIntegerError, span: &Span) -> Self { + let message = format!( + "integer operation failed due to the unsigned integer error `{:?}`", + error + ); + + Self::new_from_span(message, span) + } + pub fn synthesis(error: SynthesisError, span: &Span) -> Self { let message = format!("integer operation failed due to the synthesis error `{}`", error); diff --git a/compiler/src/statement/iteration/iteration.rs b/compiler/src/statement/iteration/iteration.rs index fc01e33d36..684f8f7dcb 100644 --- a/compiler/src/statement/iteration/iteration.rs +++ b/compiler/src/statement/iteration/iteration.rs @@ -23,6 +23,7 @@ use crate::{ GroupType, IndicatorAndConstrainedValue, Integer, + IntegerTrait, StatementResult, }; use leo_asg::IterationStatement; diff --git a/compiler/src/value/address/address.rs b/compiler/src/value/address/address.rs index fcd606f81b..0c9393ff68 100644 --- a/compiler/src/value/address/address.rs +++ b/compiler/src/value/address/address.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{errors::AddressError, ConstrainedValue, GroupType}; +use crate::{errors::AddressError, ConstrainedValue, GroupType, IntegerTrait}; use leo_ast::{InputValue, Span}; use snarkvm_dpc::{account::AccountAddress, base_dpc::instantiated::Components}; @@ -24,7 +24,7 @@ use snarkvm_gadgets::traits::utilities::{ boolean::Boolean, eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget}, select::CondSelectGadget, - uint::{UInt, UInt8}, + uint::UInt8, }; use snarkvm_r1cs::{Assignment, ConstraintSystem, SynthesisError}; use snarkvm_utilities::ToBytes; diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index 06a2001abd..808c167d53 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -28,7 +28,7 @@ use snarkvm_gadgets::traits::utilities::{ eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget}, int::{Int128, Int16, Int32, Int64, Int8}, select::CondSelectGadget, - uint::*, + uint::{Sub as UIntSub, *}, }; use snarkvm_r1cs::{ConstraintSystem, SynthesisError}; use std::fmt; @@ -83,7 +83,7 @@ impl Integer { pub fn get_bits(&self) -> Vec { let integer = self; - match_integer!(integer => integer.get_bits()) + match_integer!(integer => integer.to_bits_le()) } // pub fn get_bits_typed(&self) -> (Vec, IntegerType) { diff --git a/compiler/src/value/integer/macros.rs b/compiler/src/value/integer/macros.rs index 1ed608b8d5..1d5d7f8f9b 100644 --- a/compiler/src/value/integer/macros.rs +++ b/compiler/src/value/integer/macros.rs @@ -14,41 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use snarkvm_gadgets::traits::utilities::{ - boolean::Boolean, - int::{Int128, Int16, Int32, Int64, Int8}, - uint::{UInt128, UInt16, UInt32, UInt64, UInt8}, -}; -use std::{convert::TryInto, fmt::Debug}; - -pub trait IntegerTrait: Sized + Clone + Debug { - fn get_value(&self) -> Option; - - fn get_index(&self) -> Option; - - fn get_bits(&self) -> Vec; -} - -macro_rules! integer_trait_impl { - ($($gadget: ident)*) => ($( - impl IntegerTrait for $gadget { - fn get_value(&self) -> Option { - self.value.map(|num| num.to_string()) - } - - fn get_index(&self) -> Option { - self.value.map(|num| num.try_into().ok()).flatten() - } - - fn get_bits(&self) -> Vec { - self.bits.clone() - } - } - - )*) -} - -integer_trait_impl!(UInt8 UInt16 UInt32 UInt64 UInt128 Int8 Int16 Int32 Int64 Int128); +pub use snarkvm_gadgets::traits::utilities::integer::Integer as IntegerTrait; /// Useful macros to avoid duplicating `match` constructions. #[macro_export] @@ -125,19 +91,19 @@ macro_rules! match_integers_span { (($a: ident, $b: ident), $span: ident => $expression:expr) => { match ($a, $b) { (Integer::U8($a), Integer::U8($b)) => { - Some(Integer::U8($expression.map_err(|e| IntegerError::synthesis(e, $span))?)) + Some(Integer::U8($expression.map_err(|e| IntegerError::unsigned(e, $span))?)) + } + (Integer::U16($a), Integer::U16($b)) => { + Some(Integer::U16($expression.map_err(|e| IntegerError::unsigned(e, $span))?)) + } + (Integer::U32($a), Integer::U32($b)) => { + Some(Integer::U32($expression.map_err(|e| IntegerError::unsigned(e, $span))?)) + } + (Integer::U64($a), Integer::U64($b)) => { + Some(Integer::U64($expression.map_err(|e| IntegerError::unsigned(e, $span))?)) } - (Integer::U16($a), Integer::U16($b)) => Some(Integer::U16( - $expression.map_err(|e| IntegerError::synthesis(e, $span))?, - )), - (Integer::U32($a), Integer::U32($b)) => Some(Integer::U32( - $expression.map_err(|e| IntegerError::synthesis(e, $span))?, - )), - (Integer::U64($a), Integer::U64($b)) => Some(Integer::U64( - $expression.map_err(|e| IntegerError::synthesis(e, $span))?, - )), (Integer::U128($a), Integer::U128($b)) => Some(Integer::U128( - $expression.map_err(|e| IntegerError::synthesis(e, $span))?, + $expression.map_err(|e| IntegerError::unsigned(e, $span))?, )), (Integer::I8($a), Integer::I8($b)) => { From 670e3c0b478d12e2bb1cd7e9c461b50b78781aee Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 1 Apr 2021 13:21:22 +0200 Subject: [PATCH 091/108] deps: update snarkVM Signed-off-by: ljedrz --- Cargo.lock | 48 +++++++++++++++++++++--------------------- Cargo.toml | 10 ++++----- compiler/Cargo.toml | 14 ++++++------ state/Cargo.toml | 10 ++++----- synthesizer/Cargo.toml | 8 +++---- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7c63fefa2..dde60be4da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2571,9 +2571,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "snarkvm-algorithms" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "472ed062cdd1f54076312dd34e5fb56bd585c80c12209045f4b5bbbd368e9000" +checksum = "bdf8ca73d429824090b96f751846e37e539f24c527f1f1ce0254984ade6d17b2" dependencies = [ "blake2", "derivative", @@ -2594,9 +2594,9 @@ dependencies = [ [[package]] name = "snarkvm-curves" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdfdfa3aa137f64a7f49df03393e5d0269f133ca8c8c79e569cb3bb13181aeb2" +checksum = "64610b135b8b1152439d5dfa4f745515933366082f08651961344aa0bb5abfca" dependencies = [ "derivative", "rand", @@ -2610,9 +2610,9 @@ dependencies = [ [[package]] name = "snarkvm-derives" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a2ba967601ff2534adbc6a71a691be4285e61c83d23d54a59824f8fa80f6038" +checksum = "46c9829b6e2023b4c7c4d6c55e88fe755dd997171a6c9c063b75c28161d04326" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -2623,9 +2623,9 @@ dependencies = [ [[package]] name = "snarkvm-dpc" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4cb55898089843ba44b9f96448dcb2badcc1ce12daa8d7365d4e41513e37bc" +checksum = "491ae936e24e17c358d112ff8638b260500b5a982ecefc804861e28b5279f552" dependencies = [ "anyhow", "base58", @@ -2649,9 +2649,9 @@ dependencies = [ [[package]] name = "snarkvm-fields" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9ea954196e76fe8968fb99eced7ccf08f901ab22747c4c489bda6674a7cb39" +checksum = "8c49c69d02df11be58e07f626c9d6f5804c6dd4ccf42e425f2be8d79fe6e5bb7" dependencies = [ "bincode", "derivative", @@ -2664,9 +2664,9 @@ dependencies = [ [[package]] name = "snarkvm-gadgets" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdda42a0a6484d9f008801a8a4d494a69a4db3f7b317057a8cc3c6e4b3ef6884" +checksum = "bd6f9ac2a166d926e1755a06fdae21ce40ce6164c75c89120401b8d78f3b7ba4" dependencies = [ "derivative", "digest 0.9.0", @@ -2681,9 +2681,9 @@ dependencies = [ [[package]] name = "snarkvm-objects" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e20d13db49cedc147df06c4a6f2dd727ea25640bdf50b876f40005331767a68f" +checksum = "9bd9779ec6ab9211f34a6ba25566feb575a396f4c41cc0e002ec2d48d7560a2a" dependencies = [ "anyhow", "bincode", @@ -2702,9 +2702,9 @@ dependencies = [ [[package]] name = "snarkvm-parameters" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d35fa1819d803e45b4e99fe822e6981f177716f5384eef27245b5f6ed59a8305" +checksum = "98378f612206fc7dd44a26f4e345bd1f3ba51bd325acad1e5cc3785d14750ec5" dependencies = [ "curl", "hex", @@ -2715,15 +2715,15 @@ dependencies = [ [[package]] name = "snarkvm-profiler" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7834d57af37a31f2f280f08b61d07a04a9a4b7720819b06ca325da32a5a925f5" +checksum = "b2460ac01c25f79f5ea306e4de82a1d4105e811f868206b4fd31c0c9b62a3d7b" [[package]] name = "snarkvm-r1cs" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0838118f276e7bb673cbf3741f4966c56861aaff399a46d343fc98c12851d9eb" +checksum = "a3a0d54b15802976aff7522765dd29d5733f338612449629cc57c5a4a4d51f05" dependencies = [ "cfg-if 1.0.0", "fxhash", @@ -2736,9 +2736,9 @@ dependencies = [ [[package]] name = "snarkvm-storage" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42d92a817502878f315cc264704fa2a3d563755f16186316d8177ea685769af" +checksum = "1d76881939f008d7bba4c8cc4118d29567b5c71908ad66bef9880f8aa7c52881" dependencies = [ "anyhow", "bincode", @@ -2757,9 +2757,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5598f7f71c8aaf4fc267b5b420b2440a4d86c9243cecd57ff0af5c366217e5cc" +checksum = "c763843fa67a3aa4ce68173c8cd96b4f04aaa135a5792bc051c36eec0fe1cd73" dependencies = [ "bincode", "rand", diff --git a/Cargo.toml b/Cargo.toml index 46f2e3d7cd..c9a6ae73ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,23 +69,23 @@ path = "./synthesizer" version = "1.2.3" [dependencies.snarkvm-algorithms] -version = "0.2.1" +version = "0.2.2" #default-features = false [dependencies.snarkvm-curves] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-gadgets] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-r1cs] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-utilities] -version = "0.2.1" +version = "0.2.2" [dependencies.anyhow] version = "1.0" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 01c90ad6aa..bee182aaf9 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -50,27 +50,27 @@ path = "../asg-passes" version = "1.2.3" [dependencies.snarkvm-curves] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-fields] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-dpc] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-gadgets] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-r1cs] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-utilities] -version = "0.2.1" +version = "0.2.2" [dependencies.bincode] version = "1.3" @@ -111,7 +111,7 @@ version = "0.3" default-features = false [dev-dependencies.snarkvm-algorithms] -version = "0.2.1" +version = "0.2.2" default-features = false [dev-dependencies.tempfile] diff --git a/state/Cargo.toml b/state/Cargo.toml index 4a1174e26c..34b3e53d87 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -26,19 +26,19 @@ path = "../ast" version = "1.2.3" [dependencies.snarkvm-algorithms] -version = "0.2.1" +version = "0.2.2" #default-features = false [dependencies.snarkvm-curves] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-dpc] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-utilities] -version = "0.2.1" +version = "0.2.2" [dependencies.indexmap] version = "1.6.2" @@ -54,7 +54,7 @@ version = "0.3" version = "1.0" [dev-dependencies.snarkvm-storage] -version = "0.2.1" +version = "0.2.2" [dev-dependencies.rand_core] version = "0.6.2" diff --git a/synthesizer/Cargo.toml b/synthesizer/Cargo.toml index be2da10330..e0349f08be 100644 --- a/synthesizer/Cargo.toml +++ b/synthesizer/Cargo.toml @@ -18,19 +18,19 @@ license = "GPL-3.0" edition = "2018" [dependencies.snarkvm-curves] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-fields] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-gadgets] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.snarkvm-r1cs] -version = "0.2.1" +version = "0.2.2" default-features = false [dependencies.num-bigint] From dee5f7dc15c358e36c362cbd4fb68b95a975069c Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 1 Apr 2021 13:23:48 +0200 Subject: [PATCH 092/108] fix: use a hand-written impl of get_index Signed-off-by: ljedrz --- compiler/src/value/integer/integer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/value/integer/integer.rs b/compiler/src/value/integer/integer.rs index 808c167d53..044449b10c 100644 --- a/compiler/src/value/integer/integer.rs +++ b/compiler/src/value/integer/integer.rs @@ -31,7 +31,7 @@ use snarkvm_gadgets::traits::utilities::{ uint::{Sub as UIntSub, *}, }; use snarkvm_r1cs::{ConstraintSystem, SynthesisError}; -use std::fmt; +use std::{convert::TryInto, fmt}; /// An integer type enum wrapping the integer value. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd)] @@ -113,7 +113,7 @@ impl Integer { pub fn to_usize(&self) -> Option { let unsigned_integer = self; - match_unsigned_integer!(unsigned_integer => unsigned_integer.get_index()) + match_unsigned_integer!(unsigned_integer => unsigned_integer.value.map(|num| num.try_into().ok()).flatten()) } pub fn get_type(&self) -> IntegerType { From f55e880c434e9704924c0cbbe5bde69d0a7cc088 Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 7 Apr 2021 19:39:53 +0300 Subject: [PATCH 093/108] adds check for already existing functions --- asg/src/error/mod.rs | 7 +++++++ asg/src/program/mod.rs | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index 8dd53d098f..cff66e4116 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -172,6 +172,13 @@ impl AsgConvertError { ) } + pub fn duplicate_function_definition(name: &str, span: &Span) -> Self { + Self::new_from_span( + format!("duplicate definition, function with name \"{}\" already exists", name), + span, + ) + } + pub fn index_into_non_tuple(name: &str, span: &Span) -> Self { Self::new_from_span(format!("failed to index into non-tuple '{}'", name), span) } diff --git a/asg/src/program/mod.rs b/asg/src/program/mod.rs index c38ab404e5..868b46e8b3 100644 --- a/asg/src/program/mod.rs +++ b/asg/src/program/mod.rs @@ -266,7 +266,13 @@ impl<'a> Program<'a> { asg_function.fill_from_ast(function)?; - functions.insert(name.name.to_string(), asg_function); + let name = name.name.to_string(); + + if functions.contains_key(&name) { + return Err(AsgConvertError::duplicate_function_definition(&name, &function.span)); + } + + functions.insert(name, asg_function); } let mut circuits = IndexMap::new(); From 8ac7440daa87988e6c688c1ddf44f81a200c7b88 Mon Sep 17 00:00:00 2001 From: damirka Date: Wed, 7 Apr 2021 20:20:58 +0300 Subject: [PATCH 094/108] adds test, expects asg error --- compiler/tests/function/duplicate_definition.leo | 7 +++++++ compiler/tests/function/mod.rs | 8 ++++++++ 2 files changed, 15 insertions(+) create mode 100644 compiler/tests/function/duplicate_definition.leo diff --git a/compiler/tests/function/duplicate_definition.leo b/compiler/tests/function/duplicate_definition.leo new file mode 100644 index 0000000000..cddc9ce7f2 --- /dev/null +++ b/compiler/tests/function/duplicate_definition.leo @@ -0,0 +1,7 @@ +function main() { + console.log("{}", 1u8); +} + +function main() { + console.log("{}", 2u8); +} \ No newline at end of file diff --git a/compiler/tests/function/mod.rs b/compiler/tests/function/mod.rs index 6de6cd8153..8dfb865d90 100644 --- a/compiler/tests/function/mod.rs +++ b/compiler/tests/function/mod.rs @@ -211,3 +211,11 @@ fn test_array_params_direct_call() { assert_satisfied(program); } + +#[test] +fn test_duplicate_function_definition() { + let program_string = include_str!("duplicate_definition.leo"); + let error = parse_program(program_string).err().unwrap(); + + expect_asg_error(error); +} From aa0e5767732e8b55a28d5f0bea73145a4d11228d Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 7 Apr 2021 14:31:44 -0700 Subject: [PATCH 095/108] edit duplicate function message --- asg/src/error/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asg/src/error/mod.rs b/asg/src/error/mod.rs index cff66e4116..7ee1eb62cf 100644 --- a/asg/src/error/mod.rs +++ b/asg/src/error/mod.rs @@ -174,7 +174,7 @@ impl AsgConvertError { pub fn duplicate_function_definition(name: &str, span: &Span) -> Self { Self::new_from_span( - format!("duplicate definition, function with name \"{}\" already exists", name), + format!("a function named \"{}\" already exists in this scope", name), span, ) } From 34fd7283c8f8ce306e6f55e88924f4a4d7c15113 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 7 Apr 2021 17:10:07 -0700 Subject: [PATCH 096/108] fix package name check --- package/src/package.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/src/package.rs b/package/src/package.rs index f5c46e2696..ca26c6f3bd 100644 --- a/package/src/package.rs +++ b/package/src/package.rs @@ -71,7 +71,7 @@ impl Package { // Iterate and check that the package name is valid. for current in package_name.chars() { // Check that the package name is lowercase. - if !current.is_ascii_lowercase() && current != '-' { + if current.is_ascii_uppercase() && current != '-' { tracing::error!("Project names must be all lowercase"); return false; } From 0a3fb3003512320c648f3fb54a442cd68b250782 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 7 Apr 2021 17:18:14 -0700 Subject: [PATCH 097/108] package names cannot start with a number --- package/src/package.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/package/src/package.rs b/package/src/package.rs index ca26c6f3bd..4ae9e2e92d 100644 --- a/package/src/package.rs +++ b/package/src/package.rs @@ -68,6 +68,12 @@ impl Package { return false; } + // Check that the first character is not a number. + if previous.is_numeric() { + tracing::error!("Project names cannot begin with a number"); + return false; + } + // Iterate and check that the package name is valid. for current in package_name.chars() { // Check that the package name is lowercase. @@ -267,6 +273,8 @@ mod tests { assert!(Package::is_package_name_valid("foo")); assert!(Package::is_package_name_valid("foo-bar")); assert!(Package::is_package_name_valid("foo-bar-baz")); + assert!(Package::is_package_name_valid("foo1")); + assert!(Package::is_package_name_valid("foo-1")); assert!(!Package::is_package_name_valid("")); assert!(!Package::is_package_name_valid("-")); @@ -279,5 +287,6 @@ mod tests { assert!(!Package::is_package_name_valid("foo*bar")); assert!(!Package::is_package_name_valid("foo,bar")); assert!(!Package::is_package_name_valid("foo_bar")); + assert!(!Package::is_package_name_valid("1-foo")); } } From 45986d598ca1b513b8edfbabe66cb40c442f4bab Mon Sep 17 00:00:00 2001 From: damirka Date: Thu, 8 Apr 2021 10:45:04 +0300 Subject: [PATCH 098/108] adds %s to abnf converter and md --- grammar/abnf-grammar.md | 206 ++++++++++++++++++++-------------------- grammar/src/main.rs | 9 +- 2 files changed, 106 insertions(+), 109 deletions(-) diff --git a/grammar/abnf-grammar.md b/grammar/abnf-grammar.md index a96d83885f..7291db3633 100644 --- a/grammar/abnf-grammar.md +++ b/grammar/abnf-grammar.md @@ -84,7 +84,7 @@ all denote the sequence of terminals '1 3 10'; e.g. %x30-39 denotes any singleton sequence of terminals 'n' with 48 <= n <= 57 (an ASCII digit); (iii) case-sensitive ASCII strings, -e.g. "Ab" denotes the sequence of terminals '65 98'; +e.g. %s"Ab" denotes the sequence of terminals '65 98'; and (iv) case-insensitive ASCII strings, e.g. %i"ab", or just "ab", denotes any sequence of terminals among @@ -465,7 +465,7 @@ described above. newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; +Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -475,7 +475,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[newline](#user-content-newline), [horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space)_; +Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_; There are two kinds of comments in Leo, as in other languages. @@ -510,7 +510,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star / not-star rest-of-block-comment ``` -Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [not-star](#user-content-not-star), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_; @@ -520,7 +520,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash)_; +Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_; @@ -536,40 +536,40 @@ They cannot be used as identifiers. ```abnf -keyword = "address" - / "as" - / "bool" - / "circuit" - / "console" - / "const" - / "else" - / "false" - / "field" - / "for" - / "function" - / "group" - / "i8" - / "i16" - / "i32" - / "i64" - / "i128" - / "if" - / "import" - / "in" - / "input" - / "let" - / "mut" - / "return" - / "Self" - / "self" - / "static" - / "string" - / "true" - / "u8" - / "u16" - / "u32" - / "u64" - / "u128" +keyword = %s"address" + / %s"as" + / %s"bool" + / %s"circuit" + / %s"console" + / %s"const" + / %s"else" + / %s"false" + / %s"field" + / %s"for" + / %s"function" + / %s"group" + / %s"i8" + / %s"i16" + / %s"i32" + / %s"i64" + / %s"i128" + / %s"if" + / %s"import" + / %s"in" + / %s"input" + / %s"let" + / %s"mut" + / %s"return" + / %s"Self" + / %s"self" + / %s"static" + / %s"string" + / %s"true" + / %s"u8" + / %s"u16" + / %s"u32" + / %s"u64" + / %s"u128" ``` The following rules define (ASCII) digits @@ -625,7 +625,7 @@ Thus an address always consists of 63 characters. ```abnf -address = "aleo1" 58( lowercase-letter / digit ) +address = %s"aleo1" 58( lowercase-letter / digit ) ``` A formatted string is a sequence of characters, other than double quote, @@ -734,7 +734,7 @@ Unsigned literals are naturals followed by unsigned types. ```abnf -unsigned-literal = natural ( "u8" / "u16" / "u32" / "u64" / "u128" ) +unsigned-literal = natural ( %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" ) ``` Go to: _[natural](#user-content-natural)_; @@ -744,7 +744,7 @@ Signed literals are integers followed by signed types. ```abnf -signed-literal = integer ( "i8" / "i16" / "i32" / "i64" / "i128" ) +signed-literal = integer ( %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" ) ``` Go to: _[integer](#user-content-integer)_; @@ -754,7 +754,7 @@ Field literals are integers followed by the type of field elements. ```abnf -field-literal = integer "field" +field-literal = integer %s"field" ``` Go to: _[integer](#user-content-integer)_; @@ -768,7 +768,7 @@ therefore, it is defined in the syntactic grammar. ```abnf -product-group-literal = integer "group" +product-group-literal = integer %s"group" ``` Go to: _[integer](#user-content-integer)_; @@ -778,7 +778,7 @@ Boolean literals are the usual two. ```abnf -boolean-literal = "true" / "false" +boolean-literal = %s"true" / %s"false" ``` An address literal is an address wrapped into an indication of address, @@ -786,7 +786,7 @@ to differentiate it from an identifier. ```abnf -address-literal = "address" "(" address ")" +address-literal = %s"address" "(" address ")" ``` Go to: _[address](#user-content-address)_; @@ -807,7 +807,7 @@ atomic-literal = untyped-literal / address-literal ``` -Go to: _[product-group-literal](#user-content-product-group-literal), [unsigned-literal](#user-content-unsigned-literal), [address-literal](#user-content-address-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [signed-literal](#user-content-signed-literal), [field-literal](#user-content-field-literal)_; +Go to: _[signed-literal](#user-content-signed-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [unsigned-literal](#user-content-unsigned-literal), [product-group-literal](#user-content-product-group-literal), [address-literal](#user-content-address-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -863,7 +863,7 @@ symbol = "!" / "&&" / "||" / "{" / "}" / "," / "." / ".." / "..." / ";" / ":" / "::" / "?" / "->" / "_" - / ")group" + / %s")group" ``` Everything defined above, other than comments and whitespace, @@ -880,7 +880,7 @@ token = keyword / symbol ``` -Go to: _[formatted-string](#user-content-formatted-string), [atomic-literal](#user-content-atomic-literal), [identifier](#user-content-identifier), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name)_; +Go to: _[atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [formatted-string](#user-content-formatted-string), [annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol), [identifier](#user-content-identifier), [keyword](#user-content-keyword)_; @@ -903,12 +903,12 @@ There are unsigned and signed integer types, for five sizes. ```abnf -unsigned-type = "u8" / "u16" / "u32" / "u64" / "u128" +unsigned-type = %s"u8" / %s"u16" / %s"u32" / %s"u64" / %s"u128" ``` ```abnf -signed-type = "i8" / "i16" / "i32" / "i64" / "i128" +signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128" ``` @@ -916,7 +916,7 @@ signed-type = "i8" / "i16" / "i32" / "i64" / "i128" integer-type = unsigned-type / signed-type ``` -Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_; +Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_; The integer types, along with the field and group types, @@ -924,12 +924,12 @@ for the arithmetic types, i.e. the ones that support arithmetic operations. ```abnf -field-type = "field" +field-type = %s"field" ``` ```abnf -group-type = "group" +group-type = %s"group" ``` @@ -945,12 +945,12 @@ form the scalar types, i.e. the ones whose values do not contain (sub-)values. ```abnf -boolean-type = "bool" +boolean-type = %s"bool" ``` ```abnf -address-type = "address" +address-type = %s"address" ``` @@ -958,7 +958,7 @@ address-type = "address" scalar-type = boolean-type / arithmetic-type / address-type ``` -Go to: _[address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type)_; +Go to: _[boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type), [arithmetic-type](#user-content-arithmetic-type)_; Circuit types are denoted by identifiers and the keyword 'Self'. @@ -967,7 +967,7 @@ to denote the circuit being defined. ```abnf -self-type = "Self" +self-type = %s"Self" ``` @@ -975,7 +975,7 @@ self-type = "Self" circuit-type = identifier / self-type ``` -Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; A tuple type consists of zero, two, or more component types. @@ -998,7 +998,7 @@ or a tuple of one or more dimensions. array-type = "[" type ";" array-dimensions "]" ``` -Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_; @@ -1019,7 +1019,7 @@ i.e. types whose values contain (sub-)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_; +Go to: _[array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type)_; Scalar and aggregate types form all the types. @@ -1052,7 +1052,7 @@ Go to: _[integer](#user-content-integer)_; ```abnf -affine-group-literal = "(" group-coordinate "," group-coordinate ")group" +affine-group-literal = "(" group-coordinate "," group-coordinate %s")group" ``` Go to: _[group-coordinate](#user-content-group-coordinate)_; @@ -1098,8 +1098,8 @@ by putting parentheses around it. ```abnf primary-expression = identifier - / "self" - / "input" + / %s"self" + / %s"input" / literal / "(" expression ")" / tuple-expression @@ -1107,7 +1107,7 @@ primary-expression = identifier / circuit-expression ``` -Go to: _[expression](#user-content-expression), [array-expression](#user-content-array-expression), [identifier](#user-content-identifier), [circuit-expression](#user-content-circuit-expression), [tuple-expression](#user-content-tuple-expression), [literal](#user-content-literal)_; +Go to: _[identifier](#user-content-identifier), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [literal](#user-content-literal), [tuple-expression](#user-content-tuple-expression), [expression](#user-content-expression)_; Tuple expressions construct tuples. @@ -1195,7 +1195,7 @@ circuit-construction = circuit-type "{" "}" ``` -Go to: _[circuit-type](#user-content-circuit-type), [circuit-inline-element](#user-content-circuit-inline-element)_; +Go to: _[circuit-inline-element](#user-content-circuit-inline-element), [circuit-type](#user-content-circuit-type)_; @@ -1254,7 +1254,7 @@ postfix-expression = primary-expression / postfix-expression "[" [expression] ".." [expression] "]" ``` -Go to: _[postfix-expression](#user-content-postfix-expression), [function-arguments](#user-content-function-arguments), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [natural](#user-content-natural), [expression](#user-content-expression)_; +Go to: _[natural](#user-content-natural), [identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [postfix-expression](#user-content-postfix-expression), [primary-expression](#user-content-primary-expression), [function-arguments](#user-content-function-arguments), [expression](#user-content-expression)_; Unary operators have the highest operator precedence. @@ -1268,7 +1268,7 @@ unary-expression = postfix-expression / "-" unary-expression ``` -Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_; +Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_; Next in the operator precedence is casting. @@ -1276,10 +1276,10 @@ Next in the operator precedence is casting. ```abnf cast-expression = unary-expression - / cast-expression "as" type + / cast-expression %s"as" type ``` -Go to: _[cast-expression](#user-content-cast-expression), [type](#user-content-type), [unary-expression](#user-content-unary-expression)_; +Go to: _[unary-expression](#user-content-unary-expression), [type](#user-content-type), [cast-expression](#user-content-cast-expression)_; Next in the operator precedence is exponentiation, @@ -1293,7 +1293,7 @@ exponential-expression = cast-expression / exponential-expression "**" cast-expression ``` -Go to: _[exponential-expression](#user-content-exponential-expression), [cast-expression](#user-content-cast-expression)_; +Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_; Next in precedence come multiplication and division, both left-associative. @@ -1317,7 +1317,7 @@ additive-expression = multiplicative-expression / additive-expression "-" multiplicative-expression ``` -Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_; +Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_; Next in the precedence order are ordering relations. @@ -1345,7 +1345,7 @@ equality-expression = ordering-expression / equality-expression "!=" ordering-expression ``` -Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_; +Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_; Next come conjunctive expressions, left-associative. @@ -1356,7 +1356,7 @@ conjunctive-expression = equality-expression / conjunctive-expression "&&" equality-expression ``` -Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [equality-expression](#user-content-equality-expression)_; +Go to: _[equality-expression](#user-content-equality-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; Next come disjunctive expressions, left-associative. @@ -1367,7 +1367,7 @@ disjunctive-expression = conjunctive-expression / disjunctive-expression "||" conjunctive-expression ``` -Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_; +Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_; Finally we have conditional expressions. @@ -1412,7 +1412,7 @@ statement = expression-statement / block ``` -Go to: _[conditional-statement](#user-content-conditional-statement), [loop-statement](#user-content-loop-statement), [variable-definition-statement](#user-content-variable-definition-statement), [assignment-statement](#user-content-assignment-statement), [expression-statement](#user-content-expression-statement), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [block](#user-content-block)_; +Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [return-statement](#user-content-return-statement), [loop-statement](#user-content-loop-statement), [block](#user-content-block), [console-statement](#user-content-console-statement), [conditional-statement](#user-content-conditional-statement), [expression-statement](#user-content-expression-statement), [assignment-statement](#user-content-assignment-statement)_; @@ -1436,7 +1436,7 @@ and does not end with a semicolon. ```abnf -return-statement = "return" expression +return-statement = %s"return" expression ``` Go to: _[expression](#user-content-expression)_; @@ -1450,12 +1450,12 @@ and just one initializing expression. ```abnf -variable-definition-statement = ( "let" / "const" ) +variable-definition-statement = ( %s"let" / %s"const" ) identifier-or-identifiers [ ":" type ] "=" expression ";" ``` -Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; +Go to: _[type](#user-content-type), [expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_; @@ -1475,20 +1475,20 @@ Note that blocks are required in all branches, not merely statements. ```abnf -branch = "if" expression block +branch = %s"if" expression block ``` -Go to: _[expression](#user-content-expression), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [expression](#user-content-expression)_; ```abnf conditional-statement = branch - / branch "else" block - / branch "else" conditional-statement + / branch %s"else" block + / branch %s"else" conditional-statement ``` -Go to: _[branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block)_; +Go to: _[conditional-statement](#user-content-conditional-statement), [block](#user-content-block), [branch](#user-content-branch)_; A loop statement implicitly defines a loop variable @@ -1497,10 +1497,10 @@ The body is a block. ```abnf -loop-statement = "for" identifier "in" expression ".." expression block +loop-statement = %s"for" identifier %s"in" expression ".." expression block ``` -Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [expression](#user-content-expression)_; +Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_; An assignment statement is straightforward. @@ -1532,7 +1532,7 @@ There are three kinds of print commands. ```abnf -console-statement = "console" "." console-call +console-statement = %s"console" "." console-call ``` Go to: _[console-call](#user-content-console-call)_; @@ -1544,12 +1544,12 @@ console-call = assert-call / print-call ``` -Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_; +Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_; ```abnf -assert-call = "assert" "(" expression ")" +assert-call = %s"assert" "(" expression ")" ``` Go to: _[expression](#user-content-expression)_; @@ -1557,7 +1557,7 @@ Go to: _[expression](#user-content-expression)_; ```abnf -print-function = "debug" / "error" / "log" +print-function = %s"debug" / %s"error" / %s"log" ``` @@ -1573,7 +1573,7 @@ Go to: _[formatted-string](#user-content-formatted-string)_; print-call = print-function print-arguments ``` -Go to: _[print-function](#user-content-print-function), [print-arguments](#user-content-print-arguments)_; +Go to: _[print-arguments](#user-content-print-arguments), [print-function](#user-content-print-function)_; An annotation consists of an annotation name (which starts with '@') @@ -1599,12 +1599,12 @@ Furthermore, any function may end with an 'input' parameter. ```abnf -function-declaration = *annotation "function" identifier +function-declaration = *annotation %s"function" identifier "(" [ function-parameters ] ")" [ "->" type ] block ``` -Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [identifier](#user-content-identifier)_; @@ -1615,12 +1615,12 @@ function-parameters = self-parameter [ "," input-parameter ] / input-parameter ``` -Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter), [input-parameter](#user-content-input-parameter)_; +Go to: _[self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs), [input-parameter](#user-content-input-parameter)_; ```abnf -self-parameter = [ "mut" / "const" ] "self" +self-parameter = [ %s"mut" / %s"const" ] %s"self" ``` @@ -1633,15 +1633,15 @@ Go to: _[function-input](#user-content-function-input)_; ```abnf -function-input = [ "const" ] identifier ":" type +function-input = [ %s"const" ] identifier ":" type ``` -Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; +Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; ```abnf -input-parameter = "input" +input-parameter = %s"input" ``` A circuit member variable declaration consists of an identifier and a type. @@ -1677,7 +1677,7 @@ as consisting of member variables and functions. ```abnf -circuit-declaration = *annotation "circuit" identifier +circuit-declaration = *annotation %s"circuit" identifier "{" member-declaration *( "," member-declaration ) "}" ``` @@ -1696,7 +1696,7 @@ to be followed by a comma, for convenience. ```abnf -import-declaration = "import" package-path +import-declaration = %s"import" package-path ``` Go to: _[package-path](#user-content-package-path)_; @@ -1705,12 +1705,12 @@ Go to: _[package-path](#user-content-package-path)_; ```abnf package-path = "*" - / identifier [ "as" identifier ] + / identifier [ %s"as" identifier ] / package-name "." package-path / "(" package-path *( "," package-path ) [","] ")" ``` -Go to: _[package-name](#user-content-package-name), [identifier](#user-content-identifier), [package-path](#user-content-package-path)_; +Go to: _[package-path](#user-content-package-path), [identifier](#user-content-identifier), [package-name](#user-content-package-name)_; Finally, we define a file as a sequence of zero or more declarations. @@ -1722,7 +1722,7 @@ declaration = import-declaration / circuit-declaration ``` -Go to: _[import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration), [circuit-declaration](#user-content-circuit-declaration)_; +Go to: _[import-declaration](#user-content-import-declaration), [circuit-declaration](#user-content-circuit-declaration), [function-declaration](#user-content-function-declaration)_; diff --git a/grammar/src/main.rs b/grammar/src/main.rs index 22465b66d2..f2bf4aacbb 100644 --- a/grammar/src/main.rs +++ b/grammar/src/main.rs @@ -198,13 +198,10 @@ fn main() -> Result<()> { // Take Leo ABNF grammar file. let grammar = include_str!("../abnf-grammar.txt"); - // A. Coglio's proposal for %s syntax for case-sensitive statements has not been implemented - // in this library, so we need to remove all occurrences of %s in the grammar file. - // Link to this proposal: https://www.kestrel.edu/people/coglio/vstte18.pdf - let grammar = &str::replace(grammar, "%s", ""); - // Parse ABNF to get list of all definitions. - let parsed = abnf::rulelist(grammar).map_err(|e| { + // Rust ABNF does not provide support for `%s` (case sensitive strings, part of + // the standard); so we need to remove all occurrences before parsing. + let parsed = abnf::rulelist(&str::replace(grammar, "%s", "")).map_err(|e| { eprintln!("{}", &e); anyhow::anyhow!(e) })?; From 66e30ba0e1b5f5e990e07a01a8e8666016ff88db Mon Sep 17 00:00:00 2001 From: damirka Date: Thu, 8 Apr 2021 17:49:08 +0300 Subject: [PATCH 099/108] makes -d and -q global --- leo/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/leo/main.rs b/leo/main.rs index 9d6c7f775e..a0784f70fe 100644 --- a/leo/main.rs +++ b/leo/main.rs @@ -46,10 +46,10 @@ use structopt::{clap::AppSettings, StructOpt}; #[derive(StructOpt, Debug)] #[structopt(name = "leo", author = "The Aleo Team ", setting = AppSettings::ColoredHelp)] struct Opt { - #[structopt(short, long, help = "Print additional information for debugging")] + #[structopt(short, global = true, help = "Print additional information for debugging")] debug: bool, - #[structopt(short, long, help = "Suppress CLI output")] + #[structopt(short, global = true, help = "Suppress CLI output")] quiet: bool, #[structopt(subcommand)] From 3b649f32f46e441c9c9ada72378c79b7f01943d0 Mon Sep 17 00:00:00 2001 From: damirka Date: Thu, 8 Apr 2021 18:12:34 +0300 Subject: [PATCH 100/108] fixes CI --- .circleci/leo-init.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/leo-init.sh b/.circleci/leo-init.sh index 47d6966001..04c975568f 100755 --- a/.circleci/leo-init.sh +++ b/.circleci/leo-init.sh @@ -1,4 +1,5 @@ mkdir hello-world -$LEO init --path hello-world || exit 1 +cd hello-world +$LEO init || exit 1 ls -la hello-world -$LEO run --path hello-world +$LEO run From e291f8e3edf8a9fc03c260fefc29d2c48f45cdba Mon Sep 17 00:00:00 2001 From: Collin Chin Date: Thu, 8 Apr 2021 13:06:31 -0700 Subject: [PATCH 101/108] Update build.rs --- leo/commands/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 303eb432b8..392859e238 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -42,7 +42,7 @@ impl Command for Build { type Output = Option<(Compiler<'static, Fq, EdwardsGroupType>, bool)>; fn log_span(&self) -> Span { - tracing::span!(tracing::Level::INFO, "Compiling") + tracing::span!(tracing::Level::INFO, "Build") } fn prelude(&self, _: Context) -> Result { From bec813b0141e720d0ddef2ed2031517e17d53885 Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 13:45:30 -0700 Subject: [PATCH 102/108] chore(leo): bump version for new release --- .resources/release-version | 2 +- Cargo.toml | 8 +++----- ast/Cargo.toml | 2 +- parser/Cargo.toml | 6 +++--- state/Cargo.toml | 1 - 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.resources/release-version b/.resources/release-version index 4367f90008..a064add5ff 100644 --- a/.resources/release-version +++ b/.resources/release-version @@ -1 +1 @@ -v1.2.3 +v1.2.3 \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index c9a6ae73ab..c33221e763 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ members = [ "parser", "state", "synthesizer", - "asg-passes", + "asg-passes" ] [dependencies.leo-ast] @@ -70,7 +70,6 @@ version = "1.2.3" [dependencies.snarkvm-algorithms] version = "0.2.2" -#default-features = false [dependencies.snarkvm-curves] version = "0.2.2" @@ -155,10 +154,9 @@ version = "0.5" version = "0.11.2" [features] -default = [] +default = [ ] ci_skip = [ "leo-compiler/ci_skip" ] -# This feature flag is used to disable `target-cpu=native` in `.cargo/config`. -noconfig = [] +noconfig = [ ] [profile.release] opt-level = 3 diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 70193122ef..4196cfc669 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -30,7 +30,7 @@ version = "2.0" [dependencies.serde] version = "1.0" -features = ["derive", "rc"] +features = [ "derive", "rc" ] [dependencies.serde_json] version = "1.0" diff --git a/parser/Cargo.toml b/parser/Cargo.toml index d2a9ba9557..947bc67f9c 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -42,15 +42,15 @@ version = "1.0" [dependencies.tracing] version = "0.1" -[dev-dependencies.criterion] -version = "0.3" - [dependencies.indexmap] version = "1.6" [dependencies.tendril] version = "0.4" +[dev-dependencies.criterion] +version = "0.3" + [features] default = [ ] ci_skip = [ ] diff --git a/state/Cargo.toml b/state/Cargo.toml index 34b3e53d87..7a71b7d9ea 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -27,7 +27,6 @@ version = "1.2.3" [dependencies.snarkvm-algorithms] version = "0.2.2" -#default-features = false [dependencies.snarkvm-curves] version = "0.2.2" From 513c6f00ac323c163af90a26ae04a2b338d77083 Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 13:49:11 -0700 Subject: [PATCH 103/108] Remove keyword from grammar toml --- grammar/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index 2e4b90f68d..da2b4a210b 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -9,8 +9,7 @@ keywords = [ "cryptography", "leo", "programming-language", - "zero-knowledge", - "leo-abnf" + "zero-knowledge" ] [dependencies] From 34a719d5a50d71d7410f5a008ff7313c3f36a072 Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 13:50:39 -0700 Subject: [PATCH 104/108] Update metadata for grammar toml --- grammar/Cargo.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index da2b4a210b..3a9f390555 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -2,8 +2,9 @@ name = "leo-abnf" version = "1.2.3" authors = [ "The Aleo Team " ] -description = "ABNF to Markdown converter" -edition = "2018" +description = "ABNF to Markdown converter for the Leo programming language" +homepage = "https://aleo.org" +repository = "https://github.com/AleoHQ/leo" keywords = [ "aleo", "cryptography", @@ -11,6 +12,10 @@ keywords = [ "programming-language", "zero-knowledge" ] +categories = [ "cryptography::cryptocurrencies", "web-programming" ] +include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] +license = "GPL-3.0" +edition = "2018" [dependencies] abnf = "0.10.2" From ccea624184801588981c604465e69b64c12fe06b Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 13:56:03 -0700 Subject: [PATCH 105/108] Remove no defaults on synthesizer --- synthesizer/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/synthesizer/Cargo.toml b/synthesizer/Cargo.toml index e0349f08be..727d79ee20 100644 --- a/synthesizer/Cargo.toml +++ b/synthesizer/Cargo.toml @@ -27,7 +27,6 @@ default-features = false [dependencies.snarkvm-gadgets] version = "0.2.2" -default-features = false [dependencies.snarkvm-r1cs] version = "0.2.2" From ed19537408ba4f0b3ba112a1ad38f6d2a8b3ff8d Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 14:02:15 -0700 Subject: [PATCH 106/108] Order workspace members --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c33221e763..cac5b25ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ path = "leo/main.rs" [workspace] members = [ "asg", + "asg-passes", "ast", "compiler", "grammar", @@ -37,7 +38,6 @@ members = [ "parser", "state", "synthesizer", - "asg-passes" ] [dependencies.leo-ast] From 62ee4c3b8b824ae4ee759663add057159cfa7263 Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 14:08:52 -0700 Subject: [PATCH 107/108] chore(leo): bump version for new release --- .resources/release-version | 2 +- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 18 +++++++++--------- asg-passes/Cargo.toml | 4 ++-- asg/Cargo.toml | 6 +++--- ast/Cargo.toml | 4 ++-- compiler/Cargo.toml | 18 +++++++++--------- grammar/Cargo.toml | 2 +- imports/Cargo.toml | 8 ++++---- input/Cargo.toml | 2 +- linter/Cargo.toml | 2 +- package/Cargo.toml | 2 +- parser/Cargo.toml | 4 ++-- state/Cargo.toml | 6 +++--- synthesizer/Cargo.toml | 2 +- 15 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.resources/release-version b/.resources/release-version index a064add5ff..8b3a0227b4 100644 --- a/.resources/release-version +++ b/.resources/release-version @@ -1 +1 @@ -v1.2.3 \ No newline at end of file +v1.3.0 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index dde60be4da..d4b0d14559 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1241,7 +1241,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leo-abnf" -version = "1.2.3" +version = "1.3.0" dependencies = [ "abnf", "anyhow", @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "leo-asg" -version = "1.2.3" +version = "1.3.0" dependencies = [ "criterion", "indexmap", @@ -1265,14 +1265,14 @@ dependencies = [ [[package]] name = "leo-asg-passes" -version = "1.2.3" +version = "1.3.0" dependencies = [ "leo-asg", ] [[package]] name = "leo-ast" -version = "1.2.3" +version = "1.3.0" dependencies = [ "anyhow", "criterion", @@ -1287,7 +1287,7 @@ dependencies = [ [[package]] name = "leo-compiler" -version = "1.2.3" +version = "1.3.0" dependencies = [ "bincode", "hex", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "leo-imports" -version = "1.2.3" +version = "1.3.0" dependencies = [ "indexmap", "leo-asg", @@ -1333,7 +1333,7 @@ dependencies = [ [[package]] name = "leo-input" -version = "1.2.3" +version = "1.3.0" dependencies = [ "from-pest", "pest", @@ -1345,7 +1345,7 @@ dependencies = [ [[package]] name = "leo-lang" -version = "1.2.3" +version = "1.3.0" dependencies = [ "anyhow", "clap", @@ -1384,11 +1384,11 @@ dependencies = [ [[package]] name = "leo-linter" -version = "1.2.3" +version = "1.3.0" [[package]] name = "leo-package" -version = "1.2.3" +version = "1.3.0" dependencies = [ "lazy_static", "serde", @@ -1401,7 +1401,7 @@ dependencies = [ [[package]] name = "leo-parser" -version = "1.2.3" +version = "1.3.0" dependencies = [ "criterion", "indexmap", @@ -1416,7 +1416,7 @@ dependencies = [ [[package]] name = "leo-state" -version = "1.2.3" +version = "1.3.0" dependencies = [ "indexmap", "leo-ast", @@ -1434,7 +1434,7 @@ dependencies = [ [[package]] name = "leo-synthesizer" -version = "1.2.3" +version = "1.3.0" dependencies = [ "num-bigint", "serde", diff --git a/Cargo.toml b/Cargo.toml index cac5b25ba6..2a16b49cdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-lang" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "The Leo programming language" homepage = "https://aleo.org" @@ -37,36 +37,36 @@ members = [ "package", "parser", "state", - "synthesizer", + "synthesizer" ] [dependencies.leo-ast] path = "./ast" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-compiler] path = "./compiler" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-imports] path = "./imports" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-input] path = "./input" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-package] path = "./package" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-state] path = "./state" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-synthesizer] path = "./synthesizer" -version = "1.2.3" +version = "1.3.0" [dependencies.snarkvm-algorithms] version = "0.2.2" diff --git a/asg-passes/Cargo.toml b/asg-passes/Cargo.toml index 4a1d5591d3..0e753358c8 100644 --- a/asg-passes/Cargo.toml +++ b/asg-passes/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-asg-passes" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "The Leo programming language" homepage = "https://aleo.org" @@ -22,4 +22,4 @@ path = "src/lib.rs" [dependencies.leo-asg] path = "../asg" -version = "1.2.3" +version = "1.3.0" diff --git a/asg/Cargo.toml b/asg/Cargo.toml index e20f56e7fd..3ce2935526 100644 --- a/asg/Cargo.toml +++ b/asg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-asg" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "ASG of the Leo programming language" homepage = "https://aleo.org" @@ -30,11 +30,11 @@ version = "1.6" version = "1.0" [dependencies.leo-ast] -version = "1.2.3" +version = "1.3.0" path = "../ast" [dependencies.leo-parser] -version = "1.2.3" +version = "1.3.0" path = "../parser" [dependencies.num-bigint] diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 4196cfc669..e5c68b6240 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-ast" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Core AST of the Leo programming language" homepage = "https://aleo.org" @@ -19,7 +19,7 @@ edition = "2018" [dependencies.leo-input] path = "../input" -version = "1.2.3" +version = "1.3.0" [dependencies.indexmap] version = "1.6.2" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index bee182aaf9..140f95c915 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-compiler" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Compiler of the Leo programming language" homepage = "https://aleo.org" @@ -19,35 +19,35 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-imports] path = "../imports" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-input] path = "../input" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-package] path = "../package" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-state] path = "../state" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-asg] path = "../asg" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-parser] path = "../parser" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-asg-passes] path = "../asg-passes" -version = "1.2.3" +version = "1.3.0" [dependencies.snarkvm-curves] version = "0.2.2" diff --git a/grammar/Cargo.toml b/grammar/Cargo.toml index 3a9f390555..1e909e2653 100644 --- a/grammar/Cargo.toml +++ b/grammar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-abnf" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "ABNF to Markdown converter for the Leo programming language" homepage = "https://aleo.org" diff --git a/imports/Cargo.toml b/imports/Cargo.toml index 8ab4665f8a..c8fe120726 100644 --- a/imports/Cargo.toml +++ b/imports/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-imports" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Import parser for Leo program package dependencies" homepage = "https://aleo.org" @@ -19,15 +19,15 @@ edition = "2018" [dependencies.leo-ast] path = "../ast" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-asg] path = "../asg" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-parser] path = "../parser" -version = "1.2.3" +version = "1.3.0" [dependencies.indexmap] version = "1.6.2" diff --git a/input/Cargo.toml b/input/Cargo.toml index c3375511dd..6350d5151d 100644 --- a/input/Cargo.toml +++ b/input/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-input" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Input parser of the Leo programming language" homepage = "https://aleo.org" diff --git a/linter/Cargo.toml b/linter/Cargo.toml index f934e454bb..f07b144c9c 100644 --- a/linter/Cargo.toml +++ b/linter/Cargo.toml @@ -2,7 +2,7 @@ dependencies = { } [package] name = "leo-linter" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Linter of the Leo programming language" homepage = "https://aleo.org" diff --git a/package/Cargo.toml b/package/Cargo.toml index d3bdb61029..f608bfefb2 100644 --- a/package/Cargo.toml +++ b/package/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-package" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Package parser of the Leo programming language" homepage = "https://aleo.org" diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 947bc67f9c..90fa911858 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-parser" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "AST generated by pest from the Leo grammar rules" homepage = "https://aleo.org" @@ -24,7 +24,7 @@ harness = false [dependencies.leo-ast] path = "../ast" -version = "1.2.3" +version = "1.3.0" [dependencies.lazy_static] version = "1.3.0" diff --git a/state/Cargo.toml b/state/Cargo.toml index 7a71b7d9ea..ece7ec71fd 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-state" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "State parser of the Leo programming language" homepage = "https://aleo.org" @@ -19,11 +19,11 @@ edition = "2018" [dependencies.leo-input] path = "../input" -version = "1.2.3" +version = "1.3.0" [dependencies.leo-ast] path = "../ast" -version = "1.2.3" +version = "1.3.0" [dependencies.snarkvm-algorithms] version = "0.2.2" diff --git a/synthesizer/Cargo.toml b/synthesizer/Cargo.toml index 727d79ee20..43a26b8ef9 100644 --- a/synthesizer/Cargo.toml +++ b/synthesizer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "leo-synthesizer" -version = "1.2.3" +version = "1.3.0" authors = [ "The Aleo Team " ] description = "Circuit synthesizer of the Leo programming language" homepage = "https://aleo.org" From c336f5a704e0ed82beed6bc577465d9c1f97052a Mon Sep 17 00:00:00 2001 From: howardwu Date: Fri, 9 Apr 2021 14:19:35 -0700 Subject: [PATCH 108/108] Fix asg-passes cargo toml bug --- asg-passes/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asg-passes/Cargo.toml b/asg-passes/Cargo.toml index 0e753358c8..217e53b17c 100644 --- a/asg-passes/Cargo.toml +++ b/asg-passes/Cargo.toml @@ -13,7 +13,7 @@ keywords = [ "zero-knowledge" ] categories = [ "cryptography::cryptocurrencies", "web-programming" ] -include = [ "Cargo.toml", "leo", "README.md", "LICENSE.md" ] +include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ] license = "GPL-3.0" edition = "2018"