Merge pull request #792 from Zokrates/constant-def
Introduce constant definitions
This commit is contained in:
commit
0d804fa6a6
46 changed files with 2700 additions and 841 deletions
1
changelogs/unreleased/792-dark64
Normal file
1
changelogs/unreleased/792-dark64
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Introduce constant definitions to the language (`const` keyword)
|
|
@ -8,11 +8,12 @@
|
||||||
- [Variables](language/variables.md)
|
- [Variables](language/variables.md)
|
||||||
- [Types](language/types.md)
|
- [Types](language/types.md)
|
||||||
- [Operators](language/operators.md)
|
- [Operators](language/operators.md)
|
||||||
- [Functions](language/functions.md)
|
|
||||||
- [Control flow](language/control_flow.md)
|
- [Control flow](language/control_flow.md)
|
||||||
|
- [Constants](language/constants.md)
|
||||||
|
- [Functions](language/functions.md)
|
||||||
|
- [Generics](language/generics.md)
|
||||||
- [Imports](language/imports.md)
|
- [Imports](language/imports.md)
|
||||||
- [Comments](language/comments.md)
|
- [Comments](language/comments.md)
|
||||||
- [Generics](language/generics.md)
|
|
||||||
- [Macros](language/macros.md)
|
- [Macros](language/macros.md)
|
||||||
|
|
||||||
- [Toolbox](toolbox/index.md)
|
- [Toolbox](toolbox/index.md)
|
||||||
|
|
17
zokrates_book/src/language/constants.md
Normal file
17
zokrates_book/src/language/constants.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
## Constants
|
||||||
|
|
||||||
|
Constants must be globally defined outside all other scopes by using a `const` keyword. Constants can be set only to a constant expression.
|
||||||
|
|
||||||
|
```zokrates
|
||||||
|
{{#include ../../../zokrates_cli/examples/book/constant_definition.zok}}
|
||||||
|
```
|
||||||
|
|
||||||
|
The value of a constant can't be changed through reassignment, and it can't be redeclared.
|
||||||
|
|
||||||
|
Constants must be explicitly typed. One can reference other constants inside the expression, as long as the referenced constant is already defined.
|
||||||
|
|
||||||
|
```zokrates
|
||||||
|
{{#include ../../../zokrates_cli/examples/book/constant_reference.zok}}
|
||||||
|
```
|
||||||
|
|
||||||
|
The naming convention for constants are similar to that of variables. All characters in a constant name are usually in uppercase.
|
|
@ -44,7 +44,7 @@ from "./path/to/my/module" import main as module
|
||||||
Note that this legacy method is likely to become deprecated, so it is recommended to use the preferred way instead.
|
Note that this legacy method is likely to become deprecated, so it is recommended to use the preferred way instead.
|
||||||
### Symbols
|
### Symbols
|
||||||
|
|
||||||
Two types of symbols can be imported
|
Three types of symbols can be imported
|
||||||
|
|
||||||
#### Functions
|
#### Functions
|
||||||
Functions are imported by name. If many functions have the same name but different signatures, all of them get imported, and which one to use in a particular call is inferred.
|
Functions are imported by name. If many functions have the same name but different signatures, all of them get imported, and which one to use in a particular call is inferred.
|
||||||
|
@ -52,6 +52,9 @@ Functions are imported by name. If many functions have the same name but differe
|
||||||
#### User-defined types
|
#### User-defined types
|
||||||
User-defined types declared with the `struct` keyword are imported by name.
|
User-defined types declared with the `struct` keyword are imported by name.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
Constants declared with the `const` keyword are imported by name.
|
||||||
|
|
||||||
### Relative Imports
|
### Relative Imports
|
||||||
|
|
||||||
You can import a resource in the same folder directly, like this:
|
You can import a resource in the same folder directly, like this:
|
||||||
|
|
4
zokrates_cli/examples/book/constant_definition.zok
Normal file
4
zokrates_cli/examples/book/constant_definition.zok
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const field PRIME = 31
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
return PRIME
|
5
zokrates_cli/examples/book/constant_reference.zok
Normal file
5
zokrates_cli/examples/book/constant_reference.zok
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const field ONE = 1
|
||||||
|
const field TWO = ONE + ONE
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
return TWO
|
|
@ -0,0 +1,5 @@
|
||||||
|
const field a = 1
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
a = 2 // not allowed
|
||||||
|
return a
|
|
@ -1,10 +1,10 @@
|
||||||
def const() -> field:
|
def constant() -> field:
|
||||||
return 123123
|
return 123123
|
||||||
|
|
||||||
def add(field a,field b) -> field:
|
def add(field a, field b) -> field:
|
||||||
a=const()
|
a = constant()
|
||||||
return a+b
|
return a + b
|
||||||
|
|
||||||
def main(field a,field b) -> field:
|
def main(field a, field b) -> field:
|
||||||
field c = add(a, b+const())
|
field c = add(a, b + constant())
|
||||||
return const()
|
return constant()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
struct Bar {
|
struct Bar {}
|
||||||
}
|
|
||||||
|
const field ONE = 1
|
||||||
|
const field BAR = 21 * ONE
|
||||||
|
|
||||||
def main() -> field:
|
def main() -> field:
|
||||||
return 21
|
return BAR
|
|
@ -1,5 +1,6 @@
|
||||||
struct Baz {
|
struct Baz {}
|
||||||
}
|
|
||||||
|
const field BAZ = 123
|
||||||
|
|
||||||
def main() -> field:
|
def main() -> field:
|
||||||
return 123
|
return BAZ
|
|
@ -1,9 +1,10 @@
|
||||||
from "./baz" import Baz
|
from "./baz" import Baz
|
||||||
|
|
||||||
import "./baz"
|
|
||||||
from "./baz" import main as my_function
|
from "./baz" import main as my_function
|
||||||
|
import "./baz"
|
||||||
|
|
||||||
|
const field FOO = 144
|
||||||
|
|
||||||
def main() -> field:
|
def main() -> field:
|
||||||
field a = my_function()
|
Baz b = Baz {}
|
||||||
Baz b = Baz {}
|
assert(baz() == my_function())
|
||||||
return baz()
|
return FOO
|
|
@ -1,11 +0,0 @@
|
||||||
from "./bar" import Bar as MyBar
|
|
||||||
from "./bar" import Bar
|
|
||||||
|
|
||||||
import "./foo"
|
|
||||||
import "./bar"
|
|
||||||
|
|
||||||
def main() -> field:
|
|
||||||
MyBar my_bar = MyBar {}
|
|
||||||
Bar bar = Bar {}
|
|
||||||
assert(my_bar == bar)
|
|
||||||
return foo() + bar()
|
|
6
zokrates_cli/examples/imports/import_constants.zok
Normal file
6
zokrates_cli/examples/imports/import_constants.zok
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from "./foo" import FOO
|
||||||
|
from "./bar" import BAR
|
||||||
|
from "./baz" import BAZ
|
||||||
|
|
||||||
|
def main() -> bool:
|
||||||
|
return FOO == BAR + BAZ
|
6
zokrates_cli/examples/imports/import_functions.zok
Normal file
6
zokrates_cli/examples/imports/import_functions.zok
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import "./foo"
|
||||||
|
import "./bar"
|
||||||
|
import "./baz"
|
||||||
|
|
||||||
|
def main() -> bool:
|
||||||
|
return foo() == bar() + baz()
|
8
zokrates_cli/examples/imports/import_structs.zok
Normal file
8
zokrates_cli/examples/imports/import_structs.zok
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from "./bar" import Bar as MyBar
|
||||||
|
from "./bar" import Bar
|
||||||
|
|
||||||
|
def main():
|
||||||
|
MyBar my_bar = MyBar {}
|
||||||
|
Bar bar = Bar {}
|
||||||
|
assert(my_bar == bar)
|
||||||
|
return
|
|
@ -1,4 +1,8 @@
|
||||||
import "./foo" as d
|
from "./bar" import main as bar
|
||||||
|
from "./baz" import BAZ as baz
|
||||||
|
import "./foo" as f
|
||||||
|
|
||||||
def main() -> field:
|
def main() -> field:
|
||||||
return d()
|
field foo = f()
|
||||||
|
assert(foo == bar() + baz)
|
||||||
|
return foo
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::absy;
|
use crate::absy;
|
||||||
use crate::imports;
|
use crate::imports;
|
||||||
|
|
||||||
|
use crate::absy::SymbolDefinition;
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use zokrates_pest_ast as pest;
|
use zokrates_pest_ast as pest;
|
||||||
|
|
||||||
|
@ -10,6 +11,11 @@ impl<'ast> From<pest::File<'ast>> for absy::Module<'ast> {
|
||||||
prog.structs
|
prog.structs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(absy::SymbolDeclarationNode::from)
|
.map(absy::SymbolDeclarationNode::from)
|
||||||
|
.chain(
|
||||||
|
prog.constants
|
||||||
|
.into_iter()
|
||||||
|
.map(absy::SymbolDeclarationNode::from),
|
||||||
|
)
|
||||||
.chain(
|
.chain(
|
||||||
prog.functions
|
prog.functions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -78,7 +84,7 @@ impl<'ast> From<pest::StructDefinition<'ast>> for absy::SymbolDeclarationNode<'a
|
||||||
|
|
||||||
absy::SymbolDeclaration {
|
absy::SymbolDeclaration {
|
||||||
id,
|
id,
|
||||||
symbol: absy::Symbol::HereType(ty),
|
symbol: absy::Symbol::Here(SymbolDefinition::Struct(ty)),
|
||||||
}
|
}
|
||||||
.span(span)
|
.span(span)
|
||||||
}
|
}
|
||||||
|
@ -98,6 +104,27 @@ impl<'ast> From<pest::StructField<'ast>> for absy::StructDefinitionFieldNode<'as
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast> From<pest::ConstantDefinition<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
||||||
|
fn from(definition: pest::ConstantDefinition<'ast>) -> absy::SymbolDeclarationNode<'ast> {
|
||||||
|
use crate::absy::NodeValue;
|
||||||
|
|
||||||
|
let span = definition.span;
|
||||||
|
let id = definition.id.span.as_str();
|
||||||
|
|
||||||
|
let ty = absy::ConstantDefinition {
|
||||||
|
ty: definition.ty.into(),
|
||||||
|
expression: definition.expression.into(),
|
||||||
|
}
|
||||||
|
.span(span.clone());
|
||||||
|
|
||||||
|
absy::SymbolDeclaration {
|
||||||
|
id,
|
||||||
|
symbol: absy::Symbol::Here(SymbolDefinition::Constant(ty)),
|
||||||
|
}
|
||||||
|
.span(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast> From<pest::Function<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
impl<'ast> From<pest::Function<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
||||||
fn from(function: pest::Function<'ast>) -> absy::SymbolDeclarationNode<'ast> {
|
fn from(function: pest::Function<'ast>) -> absy::SymbolDeclarationNode<'ast> {
|
||||||
use crate::absy::NodeValue;
|
use crate::absy::NodeValue;
|
||||||
|
@ -148,7 +175,7 @@ impl<'ast> From<pest::Function<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
||||||
|
|
||||||
absy::SymbolDeclaration {
|
absy::SymbolDeclaration {
|
||||||
id,
|
id,
|
||||||
symbol: absy::Symbol::HereFunction(function),
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(function)),
|
||||||
}
|
}
|
||||||
.span(span)
|
.span(span)
|
||||||
}
|
}
|
||||||
|
@ -754,7 +781,7 @@ mod tests {
|
||||||
let expected: absy::Module = absy::Module {
|
let expected: absy::Module = absy::Module {
|
||||||
symbols: vec![absy::SymbolDeclaration {
|
symbols: vec![absy::SymbolDeclaration {
|
||||||
id: &source[4..8],
|
id: &source[4..8],
|
||||||
symbol: absy::Symbol::HereFunction(
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||||
absy::Function {
|
absy::Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
statements: vec![absy::Statement::Return(
|
statements: vec![absy::Statement::Return(
|
||||||
|
@ -771,7 +798,7 @@ mod tests {
|
||||||
.outputs(vec![UnresolvedType::FieldElement.mock()]),
|
.outputs(vec![UnresolvedType::FieldElement.mock()]),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.into()],
|
.into()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
@ -786,7 +813,7 @@ mod tests {
|
||||||
let expected: absy::Module = absy::Module {
|
let expected: absy::Module = absy::Module {
|
||||||
symbols: vec![absy::SymbolDeclaration {
|
symbols: vec![absy::SymbolDeclaration {
|
||||||
id: &source[4..8],
|
id: &source[4..8],
|
||||||
symbol: absy::Symbol::HereFunction(
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||||
absy::Function {
|
absy::Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
statements: vec![absy::Statement::Return(
|
statements: vec![absy::Statement::Return(
|
||||||
|
@ -801,7 +828,7 @@ mod tests {
|
||||||
.outputs(vec![UnresolvedType::Boolean.mock()]),
|
.outputs(vec![UnresolvedType::Boolean.mock()]),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.into()],
|
.into()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
@ -817,7 +844,7 @@ mod tests {
|
||||||
let expected: absy::Module = absy::Module {
|
let expected: absy::Module = absy::Module {
|
||||||
symbols: vec![absy::SymbolDeclaration {
|
symbols: vec![absy::SymbolDeclaration {
|
||||||
id: &source[4..8],
|
id: &source[4..8],
|
||||||
symbol: absy::Symbol::HereFunction(
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||||
absy::Function {
|
absy::Function {
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
absy::Parameter::private(
|
absy::Parameter::private(
|
||||||
|
@ -854,7 +881,7 @@ mod tests {
|
||||||
.outputs(vec![UnresolvedType::FieldElement.mock()]),
|
.outputs(vec![UnresolvedType::FieldElement.mock()]),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.into()],
|
.into()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
@ -871,7 +898,7 @@ mod tests {
|
||||||
absy::Module {
|
absy::Module {
|
||||||
symbols: vec![absy::SymbolDeclaration {
|
symbols: vec![absy::SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: absy::Symbol::HereFunction(
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||||
absy::Function {
|
absy::Function {
|
||||||
arguments: vec![absy::Parameter::private(
|
arguments: vec![absy::Parameter::private(
|
||||||
absy::Variable::new("a", ty.clone().mock()).into(),
|
absy::Variable::new("a", ty.clone().mock()).into(),
|
||||||
|
@ -887,7 +914,7 @@ mod tests {
|
||||||
signature: UnresolvedSignature::new().inputs(vec![ty.mock()]),
|
signature: UnresolvedSignature::new().inputs(vec![ty.mock()]),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.into()],
|
.into()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
@ -945,7 +972,7 @@ mod tests {
|
||||||
absy::Module {
|
absy::Module {
|
||||||
symbols: vec![absy::SymbolDeclaration {
|
symbols: vec![absy::SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: absy::Symbol::HereFunction(
|
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||||
absy::Function {
|
absy::Function {
|
||||||
arguments: vec![],
|
arguments: vec![],
|
||||||
statements: vec![absy::Statement::Return(
|
statements: vec![absy::Statement::Return(
|
||||||
|
@ -958,7 +985,7 @@ mod tests {
|
||||||
signature: UnresolvedSignature::new(),
|
signature: UnresolvedSignature::new(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.into()],
|
.into()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
|
|
@ -51,10 +51,27 @@ pub struct SymbolDeclaration<'ast> {
|
||||||
pub symbol: Symbol<'ast>,
|
pub symbol: Symbol<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
pub enum SymbolDefinition<'ast> {
|
||||||
|
Struct(StructDefinitionNode<'ast>),
|
||||||
|
Constant(ConstantDefinitionNode<'ast>),
|
||||||
|
Function(FunctionNode<'ast>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Debug for SymbolDefinition<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SymbolDefinition::Struct(s) => write!(f, "Struct({:?})", s),
|
||||||
|
SymbolDefinition::Constant(c) => write!(f, "Constant({:?})", c),
|
||||||
|
SymbolDefinition::Function(func) => write!(f, "Function({:?})", func),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub enum Symbol<'ast> {
|
pub enum Symbol<'ast> {
|
||||||
HereType(StructDefinitionNode<'ast>),
|
Here(SymbolDefinition<'ast>),
|
||||||
HereFunction(FunctionNode<'ast>),
|
|
||||||
There(SymbolImportNode<'ast>),
|
There(SymbolImportNode<'ast>),
|
||||||
Flat(FlatEmbed),
|
Flat(FlatEmbed),
|
||||||
}
|
}
|
||||||
|
@ -62,9 +79,8 @@ pub enum Symbol<'ast> {
|
||||||
impl<'ast> fmt::Debug for Symbol<'ast> {
|
impl<'ast> fmt::Debug for Symbol<'ast> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Symbol::HereType(t) => write!(f, "HereType({:?})", t),
|
Symbol::Here(k) => write!(f, "Here({:?})", k),
|
||||||
Symbol::HereFunction(fun) => write!(f, "HereFunction({:?})", fun),
|
Symbol::There(i) => write!(f, "There({:?})", i),
|
||||||
Symbol::There(t) => write!(f, "There({:?})", t),
|
|
||||||
Symbol::Flat(flat) => write!(f, "Flat({:?})", flat),
|
Symbol::Flat(flat) => write!(f, "Flat({:?})", flat),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,8 +89,15 @@ impl<'ast> fmt::Debug for Symbol<'ast> {
|
||||||
impl<'ast> fmt::Display for SymbolDeclaration<'ast> {
|
impl<'ast> fmt::Display for SymbolDeclaration<'ast> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self.symbol {
|
match self.symbol {
|
||||||
Symbol::HereType(ref t) => write!(f, "struct {} {}", self.id, t),
|
Symbol::Here(ref kind) => match kind {
|
||||||
Symbol::HereFunction(ref fun) => write!(f, "def {}{}", self.id, fun),
|
SymbolDefinition::Struct(t) => write!(f, "struct {} {}", self.id, t),
|
||||||
|
SymbolDefinition::Constant(c) => write!(
|
||||||
|
f,
|
||||||
|
"const {} {} = {}",
|
||||||
|
c.value.ty, self.id, c.value.expression
|
||||||
|
),
|
||||||
|
SymbolDefinition::Function(func) => write!(f, "def {}{}", self.id, func),
|
||||||
|
},
|
||||||
Symbol::There(ref import) => write!(f, "import {} as {}", import, self.id),
|
Symbol::There(ref import) => write!(f, "import {} as {}", import, self.id),
|
||||||
Symbol::Flat(ref flat_fun) => {
|
Symbol::Flat(ref flat_fun) => {
|
||||||
write!(f, "def {}{}:\n\t// hidden", self.id, flat_fun.signature())
|
write!(f, "def {}{}:\n\t// hidden", self.id, flat_fun.signature())
|
||||||
|
@ -146,6 +169,30 @@ impl<'ast> fmt::Display for StructDefinitionField<'ast> {
|
||||||
|
|
||||||
type StructDefinitionFieldNode<'ast> = Node<StructDefinitionField<'ast>>;
|
type StructDefinitionFieldNode<'ast> = Node<StructDefinitionField<'ast>>;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct ConstantDefinition<'ast> {
|
||||||
|
pub ty: UnresolvedTypeNode<'ast>,
|
||||||
|
pub expression: ExpressionNode<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ConstantDefinitionNode<'ast> = Node<ConstantDefinition<'ast>>;
|
||||||
|
|
||||||
|
impl<'ast> fmt::Display for ConstantDefinition<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "const {}({})", self.ty, self.expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> fmt::Debug for ConstantDefinition<'ast> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"ConstantDefinition({:?}, {:?})",
|
||||||
|
self.ty, self.expression
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An import
|
/// An import
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SymbolImport<'ast> {
|
pub struct SymbolImport<'ast> {
|
||||||
|
|
|
@ -84,6 +84,7 @@ impl<'ast> NodeValue for SymbolDeclaration<'ast> {}
|
||||||
impl<'ast> NodeValue for UnresolvedType<'ast> {}
|
impl<'ast> NodeValue for UnresolvedType<'ast> {}
|
||||||
impl<'ast> NodeValue for StructDefinition<'ast> {}
|
impl<'ast> NodeValue for StructDefinition<'ast> {}
|
||||||
impl<'ast> NodeValue for StructDefinitionField<'ast> {}
|
impl<'ast> NodeValue for StructDefinitionField<'ast> {}
|
||||||
|
impl<'ast> NodeValue for ConstantDefinition<'ast> {}
|
||||||
impl<'ast> NodeValue for Function<'ast> {}
|
impl<'ast> NodeValue for Function<'ast> {}
|
||||||
impl<'ast> NodeValue for Module<'ast> {}
|
impl<'ast> NodeValue for Module<'ast> {}
|
||||||
impl<'ast> NodeValue for SymbolImport<'ast> {}
|
impl<'ast> NodeValue for SymbolImport<'ast> {}
|
||||||
|
|
|
@ -47,6 +47,8 @@ impl ErrorInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypeMap<'ast> = HashMap<OwnedModuleId, HashMap<UserTypeId, DeclarationType<'ast>>>;
|
type TypeMap<'ast> = HashMap<OwnedModuleId, HashMap<UserTypeId, DeclarationType<'ast>>>;
|
||||||
|
type ConstantMap<'ast, T> =
|
||||||
|
HashMap<OwnedModuleId, HashMap<ConstantIdentifier<'ast>, Type<'ast, T>>>;
|
||||||
|
|
||||||
/// The global state of the program during semantic checks
|
/// The global state of the program during semantic checks
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -57,12 +59,15 @@ struct State<'ast, T> {
|
||||||
typed_modules: TypedModules<'ast, T>,
|
typed_modules: TypedModules<'ast, T>,
|
||||||
/// The user-defined types, which we keep track at this phase only. In later phases, we rely only on basic types and combinations thereof
|
/// The user-defined types, which we keep track at this phase only. In later phases, we rely only on basic types and combinations thereof
|
||||||
types: TypeMap<'ast>,
|
types: TypeMap<'ast>,
|
||||||
|
// The user-defined constants
|
||||||
|
constants: ConstantMap<'ast, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A symbol for a given name: either a type or a group of functions. Not both!
|
/// A symbol for a given name: either a type or a group of functions. Not both!
|
||||||
#[derive(PartialEq, Hash, Eq, Debug)]
|
#[derive(PartialEq, Hash, Eq, Debug)]
|
||||||
enum SymbolType<'ast> {
|
enum SymbolType<'ast> {
|
||||||
Type,
|
Type,
|
||||||
|
Constant,
|
||||||
Functions(BTreeSet<DeclarationSignature<'ast>>),
|
Functions(BTreeSet<DeclarationSignature<'ast>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,9 +79,9 @@ struct SymbolUnifier<'ast> {
|
||||||
|
|
||||||
impl<'ast> SymbolUnifier<'ast> {
|
impl<'ast> SymbolUnifier<'ast> {
|
||||||
fn insert_type<S: Into<String>>(&mut self, id: S) -> bool {
|
fn insert_type<S: Into<String>>(&mut self, id: S) -> bool {
|
||||||
let s_type = self.symbols.entry(id.into());
|
let e = self.symbols.entry(id.into());
|
||||||
match s_type {
|
match e {
|
||||||
// if anything is already called `id`, we cannot introduce this type
|
// if anything is already called `id`, we cannot introduce the symbol
|
||||||
Entry::Occupied(..) => false,
|
Entry::Occupied(..) => false,
|
||||||
// otherwise, we can!
|
// otherwise, we can!
|
||||||
Entry::Vacant(v) => {
|
Entry::Vacant(v) => {
|
||||||
|
@ -86,6 +91,19 @@ impl<'ast> SymbolUnifier<'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn insert_constant<S: Into<String>>(&mut self, id: S) -> bool {
|
||||||
|
let e = self.symbols.entry(id.into());
|
||||||
|
match e {
|
||||||
|
// if anything is already called `id`, we cannot introduce this constant
|
||||||
|
Entry::Occupied(..) => false,
|
||||||
|
// otherwise, we can!
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
v.insert(SymbolType::Constant);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_function<S: Into<String>>(
|
fn insert_function<S: Into<String>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: S,
|
id: S,
|
||||||
|
@ -96,8 +114,8 @@ impl<'ast> SymbolUnifier<'ast> {
|
||||||
// if anything is already called `id`, it depends what it is
|
// if anything is already called `id`, it depends what it is
|
||||||
Entry::Occupied(mut o) => {
|
Entry::Occupied(mut o) => {
|
||||||
match o.get_mut() {
|
match o.get_mut() {
|
||||||
// if it's a Type, then we can't introduce a function
|
// if it's a Type or a Constant, then we can't introduce a function
|
||||||
SymbolType::Type => false,
|
SymbolType::Type | SymbolType::Constant => false,
|
||||||
// if it's a Function, we can introduce it only if it has a different signature
|
// if it's a Function, we can introduce it only if it has a different signature
|
||||||
SymbolType::Functions(signatures) => signatures.insert(signature),
|
SymbolType::Functions(signatures) => signatures.insert(signature),
|
||||||
}
|
}
|
||||||
|
@ -117,6 +135,7 @@ impl<'ast, T: Field> State<'ast, T> {
|
||||||
modules,
|
modules,
|
||||||
typed_modules: HashMap::new(),
|
typed_modules: HashMap::new(),
|
||||||
types: HashMap::new(),
|
types: HashMap::new(),
|
||||||
|
constants: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +267,12 @@ pub struct ScopedVariable<'ast, T> {
|
||||||
level: usize,
|
level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> ScopedVariable<'ast, T> {
|
||||||
|
fn is_constant(&self) -> bool {
|
||||||
|
self.level == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Identifiers of different `ScopedVariable`s should not conflict, so we define them as equivalent
|
/// Identifiers of different `ScopedVariable`s should not conflict, so we define them as equivalent
|
||||||
impl<'ast, T> PartialEq for ScopedVariable<'ast, T> {
|
impl<'ast, T> PartialEq for ScopedVariable<'ast, T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
@ -325,6 +350,50 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_constant_definition(
|
||||||
|
&mut self,
|
||||||
|
id: &'ast str,
|
||||||
|
c: ConstantDefinitionNode<'ast>,
|
||||||
|
module_id: &ModuleId,
|
||||||
|
types: &TypeMap<'ast>,
|
||||||
|
) -> Result<TypedConstant<'ast, T>, ErrorInner> {
|
||||||
|
let pos = c.pos();
|
||||||
|
let ty = self.check_type(c.value.ty.clone(), module_id, &types)?;
|
||||||
|
let checked_expr = self.check_expression(c.value.expression.clone(), module_id, types)?;
|
||||||
|
|
||||||
|
match ty {
|
||||||
|
Type::FieldElement => {
|
||||||
|
FieldElementExpression::try_from_typed(checked_expr).map(TypedExpression::from)
|
||||||
|
}
|
||||||
|
Type::Boolean => {
|
||||||
|
BooleanExpression::try_from_typed(checked_expr).map(TypedExpression::from)
|
||||||
|
}
|
||||||
|
Type::Uint(bitwidth) => {
|
||||||
|
UExpression::try_from_typed(checked_expr, bitwidth).map(TypedExpression::from)
|
||||||
|
}
|
||||||
|
Type::Array(ref array_ty) => {
|
||||||
|
ArrayExpression::try_from_typed(checked_expr, *array_ty.ty.clone())
|
||||||
|
.map(TypedExpression::from)
|
||||||
|
}
|
||||||
|
Type::Struct(ref struct_ty) => {
|
||||||
|
StructExpression::try_from_typed(checked_expr, struct_ty.clone())
|
||||||
|
.map(TypedExpression::from)
|
||||||
|
}
|
||||||
|
Type::Int => Err(checked_expr), // Integers cannot be assigned
|
||||||
|
}
|
||||||
|
.map_err(|e| ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"Expression `{}` of type `{}` cannot be assigned to constant `{}` of type `{}`",
|
||||||
|
e,
|
||||||
|
e.get_type(),
|
||||||
|
id,
|
||||||
|
ty
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.map(|e| TypedConstant::new(ty, e))
|
||||||
|
}
|
||||||
|
|
||||||
fn check_struct_type_declaration(
|
fn check_struct_type_declaration(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: String,
|
id: String,
|
||||||
|
@ -378,6 +447,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
module_id: &ModuleId,
|
module_id: &ModuleId,
|
||||||
state: &mut State<'ast, T>,
|
state: &mut State<'ast, T>,
|
||||||
functions: &mut HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>,
|
functions: &mut HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>,
|
||||||
|
constants: &mut HashMap<ConstantIdentifier<'ast>, TypedConstantSymbol<'ast, T>>,
|
||||||
symbol_unifier: &mut SymbolUnifier<'ast>,
|
symbol_unifier: &mut SymbolUnifier<'ast>,
|
||||||
) -> Result<(), Vec<Error>> {
|
) -> Result<(), Vec<Error>> {
|
||||||
let mut errors: Vec<Error> = vec![];
|
let mut errors: Vec<Error> = vec![];
|
||||||
|
@ -386,76 +456,120 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
let declaration = declaration.value;
|
let declaration = declaration.value;
|
||||||
|
|
||||||
match declaration.symbol.clone() {
|
match declaration.symbol.clone() {
|
||||||
Symbol::HereType(t) => {
|
Symbol::Here(kind) => match kind {
|
||||||
match self.check_struct_type_declaration(
|
SymbolDefinition::Struct(t) => {
|
||||||
declaration.id.to_string(),
|
match self.check_struct_type_declaration(
|
||||||
t.clone(),
|
declaration.id.to_string(),
|
||||||
module_id,
|
t.clone(),
|
||||||
&state.types,
|
module_id,
|
||||||
) {
|
&state.types,
|
||||||
Ok(ty) => {
|
) {
|
||||||
match symbol_unifier.insert_type(declaration.id) {
|
Ok(ty) => {
|
||||||
false => errors.push(
|
match symbol_unifier.insert_type(declaration.id) {
|
||||||
ErrorInner {
|
false => errors.push(
|
||||||
pos: Some(pos),
|
ErrorInner {
|
||||||
message: format!(
|
pos: Some(pos),
|
||||||
"{} conflicts with another symbol",
|
message: format!(
|
||||||
declaration.id,
|
"{} conflicts with another symbol",
|
||||||
),
|
declaration.id,
|
||||||
}
|
),
|
||||||
.in_file(module_id),
|
}
|
||||||
),
|
.in_file(module_id),
|
||||||
true => {
|
|
||||||
// there should be no entry in the map for this type yet
|
|
||||||
assert!(state
|
|
||||||
.types
|
|
||||||
.entry(module_id.to_path_buf())
|
|
||||||
.or_default()
|
|
||||||
.insert(declaration.id.to_string(), ty)
|
|
||||||
.is_none());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(e) => errors.extend(e.into_iter().map(|inner| Error {
|
|
||||||
inner,
|
|
||||||
module_id: module_id.to_path_buf(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Symbol::HereFunction(f) => match self.check_function(f, module_id, &state.types) {
|
|
||||||
Ok(funct) => {
|
|
||||||
match symbol_unifier.insert_function(declaration.id, funct.signature.clone()) {
|
|
||||||
false => errors.push(
|
|
||||||
ErrorInner {
|
|
||||||
pos: Some(pos),
|
|
||||||
message: format!(
|
|
||||||
"{} conflicts with another symbol",
|
|
||||||
declaration.id,
|
|
||||||
),
|
),
|
||||||
}
|
true => {
|
||||||
.in_file(module_id),
|
// there should be no entry in the map for this type yet
|
||||||
),
|
assert!(state
|
||||||
true => {}
|
.types
|
||||||
};
|
.entry(module_id.to_path_buf())
|
||||||
|
.or_default()
|
||||||
self.functions.insert(
|
.insert(declaration.id.to_string(), ty)
|
||||||
DeclarationFunctionKey::with_location(
|
.is_none());
|
||||||
module_id.to_path_buf(),
|
}
|
||||||
declaration.id,
|
};
|
||||||
)
|
}
|
||||||
.signature(funct.signature.clone()),
|
Err(e) => errors.extend(e.into_iter().map(|inner| Error {
|
||||||
);
|
inner,
|
||||||
functions.insert(
|
module_id: module_id.to_path_buf(),
|
||||||
DeclarationFunctionKey::with_location(
|
})),
|
||||||
module_id.to_path_buf(),
|
}
|
||||||
declaration.id,
|
|
||||||
)
|
|
||||||
.signature(funct.signature.clone()),
|
|
||||||
TypedFunctionSymbol::Here(funct),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
SymbolDefinition::Constant(c) => {
|
||||||
errors.extend(e.into_iter().map(|inner| inner.in_file(module_id)));
|
match self.check_constant_definition(declaration.id, c, module_id, &state.types)
|
||||||
|
{
|
||||||
|
Ok(c) => {
|
||||||
|
match symbol_unifier.insert_constant(declaration.id) {
|
||||||
|
false => errors.push(
|
||||||
|
ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"{} conflicts with another symbol",
|
||||||
|
declaration.id,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.in_file(module_id),
|
||||||
|
),
|
||||||
|
true => {
|
||||||
|
constants.insert(
|
||||||
|
declaration.id,
|
||||||
|
TypedConstantSymbol::Here(c.clone()),
|
||||||
|
);
|
||||||
|
self.insert_into_scope(Variable::with_id_and_type(
|
||||||
|
declaration.id,
|
||||||
|
c.get_type(),
|
||||||
|
));
|
||||||
|
assert!(state
|
||||||
|
.constants
|
||||||
|
.entry(module_id.to_path_buf())
|
||||||
|
.or_default()
|
||||||
|
.insert(declaration.id, c.get_type())
|
||||||
|
.is_none());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
errors.push(e.in_file(module_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SymbolDefinition::Function(f) => {
|
||||||
|
match self.check_function(f, module_id, &state.types) {
|
||||||
|
Ok(funct) => {
|
||||||
|
match symbol_unifier
|
||||||
|
.insert_function(declaration.id, funct.signature.clone())
|
||||||
|
{
|
||||||
|
false => errors.push(
|
||||||
|
ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"{} conflicts with another symbol",
|
||||||
|
declaration.id,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
.in_file(module_id),
|
||||||
|
),
|
||||||
|
true => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.functions.insert(
|
||||||
|
DeclarationFunctionKey::with_location(
|
||||||
|
module_id.to_path_buf(),
|
||||||
|
declaration.id,
|
||||||
|
)
|
||||||
|
.signature(funct.signature.clone()),
|
||||||
|
);
|
||||||
|
functions.insert(
|
||||||
|
DeclarationFunctionKey::with_location(
|
||||||
|
module_id.to_path_buf(),
|
||||||
|
declaration.id,
|
||||||
|
)
|
||||||
|
.signature(funct.signature.clone()),
|
||||||
|
TypedFunctionSymbol::Here(funct),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
errors.extend(e.into_iter().map(|inner| inner.in_file(module_id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Symbol::There(import) => {
|
Symbol::There(import) => {
|
||||||
|
@ -487,8 +601,16 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
.get(import.symbol_id)
|
.get(import.symbol_id)
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
match (function_candidates.len(), type_candidate) {
|
// find constant definition candidate
|
||||||
(0, Some(t)) => {
|
let const_candidate = state
|
||||||
|
.constants
|
||||||
|
.entry(import.module_id.to_path_buf())
|
||||||
|
.or_default()
|
||||||
|
.get(import.symbol_id)
|
||||||
|
.cloned();
|
||||||
|
|
||||||
|
match (function_candidates.len(), type_candidate, const_candidate) {
|
||||||
|
(0, Some(t), None) => {
|
||||||
|
|
||||||
// rename the type to the declared symbol
|
// rename the type to the declared symbol
|
||||||
let t = match t {
|
let t = match t {
|
||||||
|
@ -523,7 +645,32 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
.or_default()
|
.or_default()
|
||||||
.insert(declaration.id.to_string(), t);
|
.insert(declaration.id.to_string(), t);
|
||||||
}
|
}
|
||||||
(0, None) => {
|
(0, None, Some(ty)) => {
|
||||||
|
match symbol_unifier.insert_constant(declaration.id) {
|
||||||
|
false => {
|
||||||
|
errors.push(Error {
|
||||||
|
module_id: module_id.to_path_buf(),
|
||||||
|
inner: ErrorInner {
|
||||||
|
pos: Some(pos),
|
||||||
|
message: format!(
|
||||||
|
"{} conflicts with another symbol",
|
||||||
|
declaration.id,
|
||||||
|
),
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
true => {
|
||||||
|
constants.insert(declaration.id, TypedConstantSymbol::There(import.module_id, import.symbol_id));
|
||||||
|
self.insert_into_scope(Variable::with_id_and_type(declaration.id, ty.clone()));
|
||||||
|
|
||||||
|
state
|
||||||
|
.constants
|
||||||
|
.entry(module_id.to_path_buf())
|
||||||
|
.or_default()
|
||||||
|
.insert(declaration.id, ty);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(0, None, None) => {
|
||||||
errors.push(ErrorInner {
|
errors.push(ErrorInner {
|
||||||
pos: Some(pos),
|
pos: Some(pos),
|
||||||
message: format!(
|
message: format!(
|
||||||
|
@ -532,7 +679,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
),
|
),
|
||||||
}.in_file(module_id));
|
}.in_file(module_id));
|
||||||
}
|
}
|
||||||
(_, Some(_)) => unreachable!("collision in module we're importing from should have been caught when checking it"),
|
(_, Some(_), Some(_)) => unreachable!("collision in module we're importing from should have been caught when checking it"),
|
||||||
_ => {
|
_ => {
|
||||||
for candidate in function_candidates {
|
for candidate in function_candidates {
|
||||||
|
|
||||||
|
@ -609,6 +756,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
state: &mut State<'ast, T>,
|
state: &mut State<'ast, T>,
|
||||||
) -> Result<(), Vec<Error>> {
|
) -> Result<(), Vec<Error>> {
|
||||||
let mut checked_functions = HashMap::new();
|
let mut checked_functions = HashMap::new();
|
||||||
|
let mut checked_constants = HashMap::new();
|
||||||
|
|
||||||
// check if the module was already removed from the untyped ones
|
// check if the module was already removed from the untyped ones
|
||||||
let to_insert = match state.modules.remove(module_id) {
|
let to_insert = match state.modules.remove(module_id) {
|
||||||
|
@ -621,7 +769,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
// we need to create an entry in the types map to store types for this module
|
// we need to create an entry in the types map to store types for this module
|
||||||
state.types.entry(module_id.to_path_buf()).or_default();
|
state.types.entry(module_id.to_path_buf()).or_default();
|
||||||
|
|
||||||
// we keep track of the introduced symbols to avoid colisions between types and functions
|
// we keep track of the introduced symbols to avoid collisions between types and functions
|
||||||
let mut symbol_unifier = SymbolUnifier::default();
|
let mut symbol_unifier = SymbolUnifier::default();
|
||||||
|
|
||||||
// we go through symbol declarations and check them
|
// we go through symbol declarations and check them
|
||||||
|
@ -631,12 +779,14 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
module_id,
|
module_id,
|
||||||
state,
|
state,
|
||||||
&mut checked_functions,
|
&mut checked_functions,
|
||||||
|
&mut checked_constants,
|
||||||
&mut symbol_unifier,
|
&mut symbol_unifier,
|
||||||
)?
|
)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(TypedModule {
|
Some(TypedModule {
|
||||||
functions: checked_functions,
|
functions: checked_functions,
|
||||||
|
constants: checked_constants,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -688,7 +838,6 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
module_id: &ModuleId,
|
module_id: &ModuleId,
|
||||||
types: &TypeMap<'ast>,
|
types: &TypeMap<'ast>,
|
||||||
) -> Result<TypedFunction<'ast, T>, Vec<ErrorInner>> {
|
) -> Result<TypedFunction<'ast, T>, Vec<ErrorInner>> {
|
||||||
assert!(self.scope.is_empty());
|
|
||||||
assert!(self.return_types.is_none());
|
assert!(self.return_types.is_none());
|
||||||
|
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
|
@ -815,7 +964,6 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.return_types = None;
|
self.return_types = None;
|
||||||
assert!(self.scope.is_empty());
|
|
||||||
|
|
||||||
Ok(TypedFunction {
|
Ok(TypedFunction {
|
||||||
arguments: arguments_checked,
|
arguments: arguments_checked,
|
||||||
|
@ -1275,7 +1423,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
.map_err(|e| ErrorInner {
|
.map_err(|e| ErrorInner {
|
||||||
pos: Some(pos),
|
pos: Some(pos),
|
||||||
message: format!(
|
message: format!(
|
||||||
"Expression {} of type {} cannot be assigned to {} of type {}",
|
"Expression `{}` of type `{}` cannot be assigned to `{}` of type `{}`",
|
||||||
e,
|
e,
|
||||||
e.get_type(),
|
e.get_type(),
|
||||||
var.clone(),
|
var.clone(),
|
||||||
|
@ -1408,10 +1556,16 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
// check that the assignee is declared
|
// check that the assignee is declared
|
||||||
match assignee.value {
|
match assignee.value {
|
||||||
Assignee::Identifier(variable_name) => match self.get_scope(&variable_name) {
|
Assignee::Identifier(variable_name) => match self.get_scope(&variable_name) {
|
||||||
Some(var) => Ok(TypedAssignee::Identifier(Variable::with_id_and_type(
|
Some(var) => match var.is_constant() {
|
||||||
variable_name,
|
true => Err(ErrorInner {
|
||||||
var.id._type.clone(),
|
pos: Some(assignee.pos()),
|
||||||
))),
|
message: format!("Assignment to constant variable `{}`", variable_name),
|
||||||
|
}),
|
||||||
|
false => Ok(TypedAssignee::Identifier(Variable::with_id_and_type(
|
||||||
|
variable_name,
|
||||||
|
var.id._type.clone(),
|
||||||
|
))),
|
||||||
|
},
|
||||||
None => Err(ErrorInner {
|
None => Err(ErrorInner {
|
||||||
pos: Some(assignee.pos()),
|
pos: Some(assignee.pos()),
|
||||||
message: format!("Variable `{}` is undeclared", variable_name),
|
message: format!("Variable `{}` is undeclared", variable_name),
|
||||||
|
@ -3094,7 +3248,7 @@ mod tests {
|
||||||
let foo: Module = Module {
|
let foo: Module = Module {
|
||||||
symbols: vec![SymbolDeclaration {
|
symbols: vec![SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock()],
|
.mock()],
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
|
@ -3134,6 +3288,7 @@ mod tests {
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: TypedConstantSymbols::default()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3151,12 +3306,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3230,12 +3385,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(f0),
|
symbol: Symbol::Here(SymbolDefinition::Function(f0)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(f1),
|
symbol: Symbol::Here(SymbolDefinition::Function(f1)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3268,12 +3423,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3321,12 +3476,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3361,12 +3516,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(function1()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function1())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3411,12 +3566,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereType(struct0()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(struct0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereType(struct1()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(struct1())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3448,12 +3603,14 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereType(StructDefinition { fields: vec![] }.mock()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
|
StructDefinition { fields: vec![] }.mock(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3488,7 +3645,7 @@ mod tests {
|
||||||
|
|
||||||
let bar = Module::with_symbols(vec![SymbolDeclaration {
|
let bar = Module::with_symbols(vec![SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock()]);
|
.mock()]);
|
||||||
|
|
||||||
|
@ -3503,7 +3660,7 @@ mod tests {
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereType(struct0()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(struct0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -3537,7 +3694,7 @@ mod tests {
|
||||||
|
|
||||||
let bar = Module::with_symbols(vec![SymbolDeclaration {
|
let bar = Module::with_symbols(vec![SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(function0()),
|
symbol: Symbol::Here(SymbolDefinition::Function(function0())),
|
||||||
}
|
}
|
||||||
.mock()]);
|
.mock()]);
|
||||||
|
|
||||||
|
@ -3545,7 +3702,7 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereType(struct0()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(struct0())),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
|
@ -3667,6 +3824,8 @@ mod tests {
|
||||||
let types = HashMap::new();
|
let types = HashMap::new();
|
||||||
|
|
||||||
let mut checker: Checker<Bn128Field> = Checker::new();
|
let mut checker: Checker<Bn128Field> = Checker::new();
|
||||||
|
checker.enter_scope();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
checker.check_statement(statement, &*MODULE_ID, &types),
|
checker.check_statement(statement, &*MODULE_ID, &types),
|
||||||
Err(vec![ErrorInner {
|
Err(vec![ErrorInner {
|
||||||
|
@ -3691,12 +3850,13 @@ mod tests {
|
||||||
let mut scope = HashSet::new();
|
let mut scope = HashSet::new();
|
||||||
scope.insert(ScopedVariable {
|
scope.insert(ScopedVariable {
|
||||||
id: Variable::field_element("a"),
|
id: Variable::field_element("a"),
|
||||||
level: 0,
|
level: 1,
|
||||||
});
|
});
|
||||||
scope.insert(ScopedVariable {
|
scope.insert(ScopedVariable {
|
||||||
id: Variable::field_element("b"),
|
id: Variable::field_element("b"),
|
||||||
level: 0,
|
level: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut checker: Checker<Bn128Field> = new_with_args(scope, 1, HashSet::new());
|
let mut checker: Checker<Bn128Field> = new_with_args(scope, 1, HashSet::new());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
checker.check_statement(statement, &*MODULE_ID, &types),
|
checker.check_statement(statement, &*MODULE_ID, &types),
|
||||||
|
@ -3762,12 +3922,12 @@ mod tests {
|
||||||
let symbols = vec![
|
let symbols = vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "bar",
|
id: "bar",
|
||||||
symbol: Symbol::HereFunction(bar),
|
symbol: Symbol::Here(SymbolDefinition::Function(bar)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
];
|
];
|
||||||
|
@ -3877,17 +4037,17 @@ mod tests {
|
||||||
let symbols = vec![
|
let symbols = vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "bar",
|
id: "bar",
|
||||||
symbol: Symbol::HereFunction(bar),
|
symbol: Symbol::Here(SymbolDefinition::Function(bar)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main),
|
symbol: Symbol::Here(SymbolDefinition::Function(main)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
];
|
];
|
||||||
|
@ -4265,12 +4425,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main),
|
symbol: Symbol::Here(SymbolDefinition::Function(main)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -4352,12 +4512,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main),
|
symbol: Symbol::Here(SymbolDefinition::Function(main)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -4468,12 +4628,12 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main),
|
symbol: Symbol::Here(SymbolDefinition::Function(main)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -4761,12 +4921,12 @@ mod tests {
|
||||||
let symbols = vec![
|
let symbols = vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main1),
|
symbol: Symbol::Here(SymbolDefinition::Function(main1)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main2),
|
symbol: Symbol::Here(SymbolDefinition::Function(main2)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
];
|
];
|
||||||
|
@ -4879,7 +5039,7 @@ mod tests {
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
symbols: vec![SymbolDeclaration {
|
symbols: vec![SymbolDeclaration {
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
symbol: Symbol::HereType(s.mock()),
|
symbol: Symbol::Here(SymbolDefinition::Struct(s.mock())),
|
||||||
}
|
}
|
||||||
.mock()],
|
.mock()],
|
||||||
};
|
};
|
||||||
|
@ -5009,7 +5169,7 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
|
@ -5018,12 +5178,12 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "Bar",
|
id: "Bar",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
|
@ -5032,7 +5192,7 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -5078,7 +5238,7 @@ mod tests {
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
symbols: vec![SymbolDeclaration {
|
symbols: vec![SymbolDeclaration {
|
||||||
id: "Bar",
|
id: "Bar",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
|
@ -5087,7 +5247,7 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock()],
|
.mock()],
|
||||||
};
|
};
|
||||||
|
@ -5111,7 +5271,7 @@ mod tests {
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
symbols: vec![SymbolDeclaration {
|
symbols: vec![SymbolDeclaration {
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
|
@ -5120,7 +5280,7 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock()],
|
.mock()],
|
||||||
};
|
};
|
||||||
|
@ -5146,7 +5306,7 @@ mod tests {
|
||||||
symbols: vec![
|
symbols: vec![
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "Foo",
|
id: "Foo",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "bar",
|
id: "bar",
|
||||||
|
@ -5155,12 +5315,12 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
SymbolDeclaration {
|
SymbolDeclaration {
|
||||||
id: "Bar",
|
id: "Bar",
|
||||||
symbol: Symbol::HereType(
|
symbol: Symbol::Here(SymbolDefinition::Struct(
|
||||||
StructDefinition {
|
StructDefinition {
|
||||||
fields: vec![StructDefinitionField {
|
fields: vec![StructDefinitionField {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
|
@ -5169,7 +5329,7 @@ mod tests {
|
||||||
.mock()],
|
.mock()],
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
),
|
)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
],
|
],
|
||||||
|
@ -5638,17 +5798,17 @@ mod tests {
|
||||||
let m = Module::with_symbols(vec![
|
let m = Module::with_symbols(vec![
|
||||||
absy::SymbolDeclaration {
|
absy::SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo_field),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo_field)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
absy::SymbolDeclaration {
|
absy::SymbolDeclaration {
|
||||||
id: "foo",
|
id: "foo",
|
||||||
symbol: Symbol::HereFunction(foo_u32),
|
symbol: Symbol::Here(SymbolDefinition::Function(foo_u32)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
absy::SymbolDeclaration {
|
absy::SymbolDeclaration {
|
||||||
id: "main",
|
id: "main",
|
||||||
symbol: Symbol::HereFunction(main),
|
symbol: Symbol::Here(SymbolDefinition::Function(main)),
|
||||||
}
|
}
|
||||||
.mock(),
|
.mock(),
|
||||||
]);
|
]);
|
||||||
|
@ -5680,6 +5840,7 @@ mod tests {
|
||||||
let types = HashMap::new();
|
let types = HashMap::new();
|
||||||
|
|
||||||
let mut checker: Checker<Bn128Field> = Checker::new();
|
let mut checker: Checker<Bn128Field> = Checker::new();
|
||||||
|
checker.enter_scope();
|
||||||
|
|
||||||
checker
|
checker
|
||||||
.check_statement(
|
.check_statement(
|
||||||
|
@ -5713,6 +5874,8 @@ mod tests {
|
||||||
let types = HashMap::new();
|
let types = HashMap::new();
|
||||||
|
|
||||||
let mut checker: Checker<Bn128Field> = Checker::new();
|
let mut checker: Checker<Bn128Field> = Checker::new();
|
||||||
|
checker.enter_scope();
|
||||||
|
|
||||||
checker
|
checker
|
||||||
.check_statement(
|
.check_statement(
|
||||||
Statement::Declaration(
|
Statement::Declaration(
|
||||||
|
@ -5763,6 +5926,8 @@ mod tests {
|
||||||
let types = HashMap::new();
|
let types = HashMap::new();
|
||||||
|
|
||||||
let mut checker: Checker<Bn128Field> = Checker::new();
|
let mut checker: Checker<Bn128Field> = Checker::new();
|
||||||
|
checker.enter_scope();
|
||||||
|
|
||||||
checker
|
checker
|
||||||
.check_statement(
|
.check_statement(
|
||||||
Statement::Declaration(
|
Statement::Declaration(
|
||||||
|
|
822
zokrates_core/src/static_analysis/constant_inliner.rs
Normal file
822
zokrates_core/src/static_analysis/constant_inliner.rs
Normal file
|
@ -0,0 +1,822 @@
|
||||||
|
use crate::typed_absy::folder::*;
|
||||||
|
use crate::typed_absy::*;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use zokrates_field::Field;
|
||||||
|
|
||||||
|
pub struct ConstantInliner<'ast, T: Field> {
|
||||||
|
modules: TypedModules<'ast, T>,
|
||||||
|
location: OwnedTypedModuleId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T: Field> ConstantInliner<'ast, T> {
|
||||||
|
pub fn new(modules: TypedModules<'ast, T>, location: OwnedTypedModuleId) -> Self {
|
||||||
|
ConstantInliner { modules, location }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inline(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||||
|
let mut inliner = ConstantInliner::new(p.modules.clone(), p.main.clone());
|
||||||
|
inliner.fold_program(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module(&self) -> &TypedModule<'ast, T> {
|
||||||
|
self.modules.get(&self.location).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_location(&mut self, location: OwnedTypedModuleId) -> OwnedTypedModuleId {
|
||||||
|
let prev = self.location.clone();
|
||||||
|
self.location = location;
|
||||||
|
prev
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_constant(&mut self, id: &Identifier) -> Option<TypedConstant<'ast, T>> {
|
||||||
|
self.modules
|
||||||
|
.get(&self.location)
|
||||||
|
.unwrap()
|
||||||
|
.constants
|
||||||
|
.get(id.clone().try_into().unwrap())
|
||||||
|
.cloned()
|
||||||
|
.map(|symbol| self.get_canonical_constant(symbol))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_canonical_constant(
|
||||||
|
&mut self,
|
||||||
|
symbol: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> TypedConstant<'ast, T> {
|
||||||
|
match symbol {
|
||||||
|
TypedConstantSymbol::There(module_id, id) => {
|
||||||
|
let location = self.change_location(module_id);
|
||||||
|
let symbol = self.module().constants.get(id).cloned().unwrap();
|
||||||
|
|
||||||
|
let symbol = self.get_canonical_constant(symbol);
|
||||||
|
let _ = self.change_location(location);
|
||||||
|
symbol
|
||||||
|
}
|
||||||
|
TypedConstantSymbol::Here(tc) => self.fold_constant(tc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T: Field> Folder<'ast, T> for ConstantInliner<'ast, T> {
|
||||||
|
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||||
|
TypedProgram {
|
||||||
|
modules: p
|
||||||
|
.modules
|
||||||
|
.into_iter()
|
||||||
|
.map(|(module_id, module)| {
|
||||||
|
self.change_location(module_id.clone());
|
||||||
|
(module_id, self.fold_module(module))
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
main: p.main,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_constant_symbol(
|
||||||
|
&mut self,
|
||||||
|
s: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> TypedConstantSymbol<'ast, T> {
|
||||||
|
let tc = self.get_canonical_constant(s);
|
||||||
|
TypedConstantSymbol::Here(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_field_expression(
|
||||||
|
&mut self,
|
||||||
|
e: FieldElementExpression<'ast, T>,
|
||||||
|
) -> FieldElementExpression<'ast, T> {
|
||||||
|
match e {
|
||||||
|
FieldElementExpression::Identifier(ref id) => match self.get_constant(id) {
|
||||||
|
Some(c) => self.fold_constant(c).try_into().unwrap(),
|
||||||
|
None => fold_field_expression(self, e),
|
||||||
|
},
|
||||||
|
e => fold_field_expression(self, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_boolean_expression(
|
||||||
|
&mut self,
|
||||||
|
e: BooleanExpression<'ast, T>,
|
||||||
|
) -> BooleanExpression<'ast, T> {
|
||||||
|
match e {
|
||||||
|
BooleanExpression::Identifier(ref id) => match self.get_constant(id) {
|
||||||
|
Some(c) => self.fold_constant(c).try_into().unwrap(),
|
||||||
|
None => fold_boolean_expression(self, e),
|
||||||
|
},
|
||||||
|
e => fold_boolean_expression(self, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_uint_expression_inner(
|
||||||
|
&mut self,
|
||||||
|
size: UBitwidth,
|
||||||
|
e: UExpressionInner<'ast, T>,
|
||||||
|
) -> UExpressionInner<'ast, T> {
|
||||||
|
match e {
|
||||||
|
UExpressionInner::Identifier(ref id) => match self.get_constant(id) {
|
||||||
|
Some(c) => {
|
||||||
|
let e: UExpression<'ast, T> = self.fold_constant(c).try_into().unwrap();
|
||||||
|
e.into_inner()
|
||||||
|
}
|
||||||
|
None => fold_uint_expression_inner(self, size, e),
|
||||||
|
},
|
||||||
|
e => fold_uint_expression_inner(self, size, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_array_expression_inner(
|
||||||
|
&mut self,
|
||||||
|
ty: &ArrayType<'ast, T>,
|
||||||
|
e: ArrayExpressionInner<'ast, T>,
|
||||||
|
) -> ArrayExpressionInner<'ast, T> {
|
||||||
|
match e {
|
||||||
|
ArrayExpressionInner::Identifier(ref id) => match self.get_constant(id) {
|
||||||
|
Some(c) => {
|
||||||
|
let e: ArrayExpression<'ast, T> = self.fold_constant(c).try_into().unwrap();
|
||||||
|
e.into_inner()
|
||||||
|
}
|
||||||
|
None => fold_array_expression_inner(self, ty, e),
|
||||||
|
},
|
||||||
|
e => fold_array_expression_inner(self, ty, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_struct_expression_inner(
|
||||||
|
&mut self,
|
||||||
|
ty: &StructType<'ast, T>,
|
||||||
|
e: StructExpressionInner<'ast, T>,
|
||||||
|
) -> StructExpressionInner<'ast, T> {
|
||||||
|
match e {
|
||||||
|
StructExpressionInner::Identifier(ref id) => match self.get_constant(id) {
|
||||||
|
Some(c) => {
|
||||||
|
let e: StructExpression<'ast, T> = self.fold_constant(c).try_into().unwrap();
|
||||||
|
e.into_inner()
|
||||||
|
}
|
||||||
|
None => fold_struct_expression_inner(self, ty, e),
|
||||||
|
},
|
||||||
|
e => fold_struct_expression_inner(self, ty, e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::typed_absy::types::DeclarationSignature;
|
||||||
|
use crate::typed_absy::{
|
||||||
|
DeclarationFunctionKey, DeclarationType, FieldElementExpression, GType, Identifier,
|
||||||
|
TypedConstant, TypedExpression, TypedFunction, TypedFunctionSymbol, TypedStatement,
|
||||||
|
};
|
||||||
|
use zokrates_field::Bn128Field;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_const_field() {
|
||||||
|
// const field a = 1
|
||||||
|
//
|
||||||
|
// def main() -> field:
|
||||||
|
// return a
|
||||||
|
|
||||||
|
let const_id = "a";
|
||||||
|
let main: TypedFunction<Bn128Field> = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
FieldElementExpression::Identifier(Identifier::from(const_id)).into(),
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let constants: TypedConstantSymbols<_> = vec![(
|
||||||
|
const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(Bn128Field::from(1))),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: constants.clone(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
|
||||||
|
let expected_main = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(1)).into(),
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(expected_main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants,
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_const_boolean() {
|
||||||
|
// const bool a = true
|
||||||
|
//
|
||||||
|
// def main() -> bool:
|
||||||
|
// return a
|
||||||
|
|
||||||
|
let const_id = "a";
|
||||||
|
let main: TypedFunction<Bn128Field> = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![BooleanExpression::Identifier(
|
||||||
|
Identifier::from(const_id),
|
||||||
|
)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Boolean]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let constants: TypedConstantSymbols<_> = vec![(
|
||||||
|
const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::Boolean,
|
||||||
|
TypedExpression::Boolean(BooleanExpression::Value(true)),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Boolean]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: constants.clone(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
|
||||||
|
let expected_main = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
BooleanExpression::Value(true).into()
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Boolean]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Boolean]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(expected_main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants,
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_const_uint() {
|
||||||
|
// const u32 a = 0x00000001
|
||||||
|
//
|
||||||
|
// def main() -> u32:
|
||||||
|
// return a
|
||||||
|
|
||||||
|
let const_id = "a";
|
||||||
|
let main: TypedFunction<Bn128Field> = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![UExpressionInner::Identifier(
|
||||||
|
Identifier::from(const_id),
|
||||||
|
)
|
||||||
|
.annotate(UBitwidth::B32)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let constants: TypedConstantSymbols<_> = vec![(
|
||||||
|
const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::Uint(UBitwidth::B32),
|
||||||
|
UExpressionInner::Value(1u128)
|
||||||
|
.annotate(UBitwidth::B32)
|
||||||
|
.into(),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: constants.clone(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
|
||||||
|
let expected_main = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![UExpressionInner::Value(1u128)
|
||||||
|
.annotate(UBitwidth::B32)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::Uint(UBitwidth::B32)]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(expected_main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants,
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_const_field_array() {
|
||||||
|
// const field[2] a = [2, 2]
|
||||||
|
//
|
||||||
|
// def main() -> field:
|
||||||
|
// return a[0] + a[1]
|
||||||
|
|
||||||
|
let const_id = "a";
|
||||||
|
let main: TypedFunction<Bn128Field> = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||||
|
FieldElementExpression::Select(
|
||||||
|
box ArrayExpressionInner::Identifier(Identifier::from(const_id))
|
||||||
|
.annotate(GType::FieldElement, 2usize),
|
||||||
|
box UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
FieldElementExpression::Select(
|
||||||
|
box ArrayExpressionInner::Identifier(Identifier::from(const_id))
|
||||||
|
.annotate(GType::FieldElement, 2usize),
|
||||||
|
box UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let constants: TypedConstantSymbols<_> = vec![(
|
||||||
|
const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::Array(
|
||||||
|
ArrayExpressionInner::Value(
|
||||||
|
vec![
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.annotate(GType::FieldElement, 2usize),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: constants.clone(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
|
||||||
|
let expected_main = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||||
|
FieldElementExpression::Select(
|
||||||
|
box ArrayExpressionInner::Value(
|
||||||
|
vec![
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.annotate(GType::FieldElement, 2usize),
|
||||||
|
box UExpressionInner::Value(0u128).annotate(UBitwidth::B32),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
FieldElementExpression::Select(
|
||||||
|
box ArrayExpressionInner::Value(
|
||||||
|
vec![
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.annotate(GType::FieldElement, 2usize),
|
||||||
|
box UExpressionInner::Value(1u128).annotate(UBitwidth::B32),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(expected_main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants,
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_nested_const_field() {
|
||||||
|
// const field a = 1
|
||||||
|
// const field b = a + 1
|
||||||
|
//
|
||||||
|
// def main() -> field:
|
||||||
|
// return b
|
||||||
|
|
||||||
|
let const_a_id = "a";
|
||||||
|
let const_b_id = "b";
|
||||||
|
|
||||||
|
let main: TypedFunction<Bn128Field> = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
FieldElementExpression::Identifier(Identifier::from(const_b_id)).into(),
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: vec![
|
||||||
|
(
|
||||||
|
const_a_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||||
|
Bn128Field::from(1),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
const_b_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Add(
|
||||||
|
box FieldElementExpression::Identifier(Identifier::from(
|
||||||
|
const_a_id,
|
||||||
|
)),
|
||||||
|
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
|
||||||
|
let expected_main = TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||||
|
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||||
|
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||||
|
)
|
||||||
|
.into()])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(expected_main),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: vec![
|
||||||
|
(
|
||||||
|
const_a_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||||
|
Bn128Field::from(1),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
const_b_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Add(
|
||||||
|
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||||
|
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inline_imported_constant() {
|
||||||
|
// ---------------------
|
||||||
|
// module `foo`
|
||||||
|
// --------------------
|
||||||
|
// const field FOO = 42
|
||||||
|
//
|
||||||
|
// def main():
|
||||||
|
// return
|
||||||
|
//
|
||||||
|
// ---------------------
|
||||||
|
// module `main`
|
||||||
|
// ---------------------
|
||||||
|
// from "foo" import FOO
|
||||||
|
//
|
||||||
|
// def main() -> field:
|
||||||
|
// return FOO
|
||||||
|
|
||||||
|
let foo_const_id = "FOO";
|
||||||
|
let foo_module = TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main")
|
||||||
|
.signature(DeclarationSignature::new().inputs(vec![]).outputs(vec![])),
|
||||||
|
TypedFunctionSymbol::Here(TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![],
|
||||||
|
signature: DeclarationSignature::new().inputs(vec![]).outputs(vec![]),
|
||||||
|
}),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: vec![(
|
||||||
|
foo_const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||||
|
Bn128Field::from(42),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let main_module = TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
FieldElementExpression::Identifier(Identifier::from(foo_const_id)).into(),
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
}),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: vec![(
|
||||||
|
foo_const_id,
|
||||||
|
TypedConstantSymbol::There(OwnedTypedModuleId::from("foo"), foo_const_id),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![
|
||||||
|
("main".into(), main_module),
|
||||||
|
("foo".into(), foo_module.clone()),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let program = ConstantInliner::inline(program);
|
||||||
|
let expected_main_module = TypedModule {
|
||||||
|
functions: vec![(
|
||||||
|
DeclarationFunctionKey::with_location("main", "main").signature(
|
||||||
|
DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
),
|
||||||
|
TypedFunctionSymbol::Here(TypedFunction {
|
||||||
|
arguments: vec![],
|
||||||
|
statements: vec![TypedStatement::Return(vec![
|
||||||
|
FieldElementExpression::Number(Bn128Field::from(42)).into(),
|
||||||
|
])],
|
||||||
|
signature: DeclarationSignature::new()
|
||||||
|
.inputs(vec![])
|
||||||
|
.outputs(vec![DeclarationType::FieldElement]),
|
||||||
|
}),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
constants: vec![(
|
||||||
|
foo_const_id,
|
||||||
|
TypedConstantSymbol::Here(TypedConstant::new(
|
||||||
|
GType::FieldElement,
|
||||||
|
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||||
|
Bn128Field::from(42),
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_program: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
|
main: "main".into(),
|
||||||
|
modules: vec![
|
||||||
|
("main".into(), expected_main_module),
|
||||||
|
("foo".into(), foo_module),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(program, expected_program)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
//! @date 2018
|
//! @date 2018
|
||||||
|
|
||||||
mod bounds_checker;
|
mod bounds_checker;
|
||||||
|
mod constant_inliner;
|
||||||
mod flat_propagation;
|
mod flat_propagation;
|
||||||
mod flatten_complex_types;
|
mod flatten_complex_types;
|
||||||
mod propagation;
|
mod propagation;
|
||||||
|
@ -28,6 +29,7 @@ use self::variable_read_remover::VariableReadRemover;
|
||||||
use self::variable_write_remover::VariableWriteRemover;
|
use self::variable_write_remover::VariableWriteRemover;
|
||||||
use crate::flat_absy::FlatProg;
|
use crate::flat_absy::FlatProg;
|
||||||
use crate::ir::Prog;
|
use crate::ir::Prog;
|
||||||
|
use crate::static_analysis::constant_inliner::ConstantInliner;
|
||||||
use crate::typed_absy::{abi::Abi, TypedProgram};
|
use crate::typed_absy::{abi::Abi, TypedProgram};
|
||||||
use crate::zir::ZirProgram;
|
use crate::zir::ZirProgram;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -73,8 +75,11 @@ impl fmt::Display for Error {
|
||||||
|
|
||||||
impl<'ast, T: Field> TypedProgram<'ast, T> {
|
impl<'ast, T: Field> TypedProgram<'ast, T> {
|
||||||
pub fn analyse(self) -> Result<(ZirProgram<'ast, T>, Abi), Error> {
|
pub fn analyse(self) -> Result<(ZirProgram<'ast, T>, Abi), Error> {
|
||||||
let r = reduce_program(self).map_err(Error::from)?;
|
// inline user-defined constants
|
||||||
|
let r = ConstantInliner::inline(self);
|
||||||
|
// reduce the program to a single function
|
||||||
|
let r = reduce_program(r).map_err(Error::from)?;
|
||||||
|
// generate abi
|
||||||
let abi = r.abi();
|
let abi = r.abi();
|
||||||
|
|
||||||
// propagate
|
// propagate
|
||||||
|
|
|
@ -264,6 +264,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
|
..m
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -547,6 +547,7 @@ pub fn reduce_program<T: Field>(p: TypedProgram<T>) -> Result<TypedProgram<T>, E
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -761,6 +762,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -826,6 +828,7 @@ mod tests {
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -959,6 +962,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1043,6 +1047,7 @@ mod tests {
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1185,6 +1190,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1269,6 +1275,7 @@ mod tests {
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1447,6 +1454,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1558,6 +1566,7 @@ mod tests {
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1646,6 +1655,7 @@ mod tests {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
constants: Default::default(),
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -65,7 +65,13 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut modules = HashMap::new();
|
let mut modules = HashMap::new();
|
||||||
modules.insert("main".into(), TypedModule { functions });
|
modules.insert(
|
||||||
|
"main".into(),
|
||||||
|
TypedModule {
|
||||||
|
functions,
|
||||||
|
constants: Default::default(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let typed_ast: TypedProgram<Bn128Field> = TypedProgram {
|
let typed_ast: TypedProgram<Bn128Field> = TypedProgram {
|
||||||
main: "main".into(),
|
main: "main".into(),
|
||||||
|
|
|
@ -9,8 +9,19 @@ pub trait Folder<'ast, T: Field>: Sized {
|
||||||
fold_program(self, p)
|
fold_program(self, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_module(&mut self, p: TypedModule<'ast, T>) -> TypedModule<'ast, T> {
|
fn fold_module(&mut self, m: TypedModule<'ast, T>) -> TypedModule<'ast, T> {
|
||||||
fold_module(self, p)
|
fold_module(self, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_constant(&mut self, c: TypedConstant<'ast, T>) -> TypedConstant<'ast, T> {
|
||||||
|
fold_constant(self, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_constant_symbol(
|
||||||
|
&mut self,
|
||||||
|
s: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> TypedConstantSymbol<'ast, T> {
|
||||||
|
fold_constant_symbol(self, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_function_symbol(
|
fn fold_function_symbol(
|
||||||
|
@ -190,10 +201,15 @@ pub trait Folder<'ast, T: Field>: Sized {
|
||||||
|
|
||||||
pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>(
|
pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
f: &mut F,
|
f: &mut F,
|
||||||
p: TypedModule<'ast, T>,
|
m: TypedModule<'ast, T>,
|
||||||
) -> TypedModule<'ast, T> {
|
) -> TypedModule<'ast, T> {
|
||||||
TypedModule {
|
TypedModule {
|
||||||
functions: p
|
constants: m
|
||||||
|
.constants
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, tc)| (key, f.fold_constant_symbol(tc)))
|
||||||
|
.collect(),
|
||||||
|
functions: m
|
||||||
.functions
|
.functions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(key, fun)| (key, f.fold_function_symbol(fun)))
|
.map(|(key, fun)| (key, f.fold_function_symbol(fun)))
|
||||||
|
@ -711,6 +727,26 @@ pub fn fold_struct_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fold_constant<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
|
f: &mut F,
|
||||||
|
c: TypedConstant<'ast, T>,
|
||||||
|
) -> TypedConstant<'ast, T> {
|
||||||
|
TypedConstant {
|
||||||
|
ty: f.fold_type(c.ty),
|
||||||
|
expression: f.fold_expression(c.expression),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fold_constant_symbol<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
|
f: &mut F,
|
||||||
|
s: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> TypedConstantSymbol<'ast, T> {
|
||||||
|
match s {
|
||||||
|
TypedConstantSymbol::Here(tc) => TypedConstantSymbol::Here(f.fold_constant(tc)),
|
||||||
|
there => there,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>(
|
pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
f: &mut F,
|
f: &mut F,
|
||||||
s: TypedFunctionSymbol<'ast, T>,
|
s: TypedFunctionSymbol<'ast, T>,
|
||||||
|
|
|
@ -61,6 +61,18 @@ pub type TypedModules<'ast, T> = HashMap<OwnedTypedModuleId, TypedModule<'ast, T
|
||||||
pub type TypedFunctionSymbols<'ast, T> =
|
pub type TypedFunctionSymbols<'ast, T> =
|
||||||
HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
|
HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
|
||||||
|
|
||||||
|
pub type ConstantIdentifier<'ast> = &'ast str;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum TypedConstantSymbol<'ast, T> {
|
||||||
|
Here(TypedConstant<'ast, T>),
|
||||||
|
There(OwnedTypedModuleId, ConstantIdentifier<'ast>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A collection of `TypedConstantSymbol`s
|
||||||
|
pub type TypedConstantSymbols<'ast, T> =
|
||||||
|
HashMap<ConstantIdentifier<'ast>, TypedConstantSymbol<'ast, T>>;
|
||||||
|
|
||||||
/// A typed program as a collection of modules, one of them being the main
|
/// A typed program as a collection of modules, one of them being the main
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
pub struct TypedProgram<'ast, T> {
|
pub struct TypedProgram<'ast, T> {
|
||||||
|
@ -135,11 +147,13 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedProgram<'ast, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A typed program as a collection of functions. Types have been resolved during semantic checking.
|
/// A typed module as a collection of functions. Types have been resolved during semantic checking.
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub struct TypedModule<'ast, T> {
|
pub struct TypedModule<'ast, T> {
|
||||||
/// Functions of the program
|
/// Functions of the module
|
||||||
pub functions: TypedFunctionSymbols<'ast, T>,
|
pub functions: TypedFunctionSymbols<'ast, T>,
|
||||||
|
/// Constants defined in module
|
||||||
|
pub constants: TypedConstantSymbols<'ast, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
|
@ -182,22 +196,31 @@ impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
|
||||||
impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> {
|
impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let res = self
|
let res = self
|
||||||
.functions
|
.constants
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, symbol)| match symbol {
|
.map(|(key, symbol)| match symbol {
|
||||||
|
TypedConstantSymbol::Here(ref tc) => {
|
||||||
|
format!("const {} {} = {}", tc.ty, key, tc.expression)
|
||||||
|
}
|
||||||
|
TypedConstantSymbol::There(ref module_id, ref id) => {
|
||||||
|
format!("from \"{}\" import {} as {}", module_id.display(), id, key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.chain(self.functions.iter().map(|(key, symbol)| match symbol {
|
||||||
TypedFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function),
|
TypedFunctionSymbol::Here(ref function) => format!("def {}{}", key.id, function),
|
||||||
TypedFunctionSymbol::There(ref fun_key) => format!(
|
TypedFunctionSymbol::There(ref fun_key) => format!(
|
||||||
"import {} from \"{}\" as {} // with signature {}",
|
"from \"{}\" import {} as {} // with signature {}",
|
||||||
fun_key.id,
|
|
||||||
fun_key.module.display(),
|
fun_key.module.display(),
|
||||||
|
fun_key.id,
|
||||||
key.id,
|
key.id,
|
||||||
key.signature
|
key.signature
|
||||||
),
|
),
|
||||||
TypedFunctionSymbol::Flat(ref flat_fun) => {
|
TypedFunctionSymbol::Flat(ref flat_fun) => {
|
||||||
format!("def {}{}:\n\t// hidden", key.id, flat_fun.signature())
|
format!("def {}{}:\n\t// hidden", key.id, flat_fun.signature())
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
write!(f, "{}", res.join("\n"))
|
write!(f, "{}", res.join("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,8 +229,13 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedModule<'ast, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"module(\n\tfunctions:\n\t\t{:?}\n)",
|
"TypedModule(\n\tFunctions:\n\t\t{:?}\n\tConstants:\n\t\t{:?}\n)",
|
||||||
self.functions
|
self.functions
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("{:?}", x))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n\t\t"),
|
||||||
|
self.constants
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| format!("{:?}", x))
|
.map(|x| format!("{:?}", x))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
|
@ -306,6 +334,36 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunction<'ast, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct TypedConstant<'ast, T> {
|
||||||
|
ty: Type<'ast, T>,
|
||||||
|
expression: TypedExpression<'ast, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TypedConstant<'ast, T> {
|
||||||
|
pub fn new(ty: Type<'ast, T>, expression: TypedExpression<'ast, T>) -> Self {
|
||||||
|
TypedConstant { ty, expression }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T: fmt::Debug> fmt::Debug for TypedConstant<'ast, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "TypedConstant({:?}, {:?})", self.ty, self.expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T: fmt::Display> fmt::Display for TypedConstant<'ast, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "const {}({})", self.ty, self.expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T: Clone> Typed<'ast, T> for TypedConstant<'ast, T> {
|
||||||
|
fn get_type(&self) -> Type<'ast, T> {
|
||||||
|
self.ty.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Something we can assign to.
|
/// Something we can assign to.
|
||||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||||
pub enum TypedAssignee<'ast, T> {
|
pub enum TypedAssignee<'ast, T> {
|
||||||
|
@ -1224,6 +1282,56 @@ impl<'ast, T> TryFrom<TypedExpression<'ast, T>> for StructExpression<'ast, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for FieldElementExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
tc: TypedConstant<'ast, T>,
|
||||||
|
) -> Result<FieldElementExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for BooleanExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tc: TypedConstant<'ast, T>) -> Result<BooleanExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for UExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tc: TypedConstant<'ast, T>) -> Result<UExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for ArrayExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tc: TypedConstant<'ast, T>) -> Result<ArrayExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for StructExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tc: TypedConstant<'ast, T>) -> Result<StructExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for IntExpression<'ast, T> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(tc: TypedConstant<'ast, T>) -> Result<IntExpression<'ast, T>, Self::Error> {
|
||||||
|
tc.expression.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> {
|
impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -16,9 +16,23 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
|
||||||
|
|
||||||
fn fold_module(
|
fn fold_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
p: TypedModule<'ast, T>,
|
m: TypedModule<'ast, T>,
|
||||||
) -> Result<TypedModule<'ast, T>, Self::Error> {
|
) -> Result<TypedModule<'ast, T>, Self::Error> {
|
||||||
fold_module(self, p)
|
fold_module(self, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_constant(
|
||||||
|
&mut self,
|
||||||
|
c: TypedConstant<'ast, T>,
|
||||||
|
) -> Result<TypedConstant<'ast, T>, Self::Error> {
|
||||||
|
fold_constant(self, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_constant_symbol(
|
||||||
|
&mut self,
|
||||||
|
s: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> Result<TypedConstantSymbol<'ast, T>, Self::Error> {
|
||||||
|
fold_constant_symbol(self, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_function_symbol(
|
fn fold_function_symbol(
|
||||||
|
@ -793,6 +807,26 @@ pub fn fold_struct_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fold_constant<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
|
f: &mut F,
|
||||||
|
c: TypedConstant<'ast, T>,
|
||||||
|
) -> Result<TypedConstant<'ast, T>, F::Error> {
|
||||||
|
Ok(TypedConstant {
|
||||||
|
ty: f.fold_type(c.ty)?,
|
||||||
|
expression: f.fold_expression(c.expression)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fold_constant_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
|
f: &mut F,
|
||||||
|
s: TypedConstantSymbol<'ast, T>,
|
||||||
|
) -> Result<TypedConstantSymbol<'ast, T>, F::Error> {
|
||||||
|
match s {
|
||||||
|
TypedConstantSymbol::Here(tc) => Ok(TypedConstantSymbol::Here(f.fold_constant(tc)?)),
|
||||||
|
there => Ok(there),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fold_function_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
pub fn fold_function_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
f: &mut F,
|
f: &mut F,
|
||||||
s: TypedFunctionSymbol<'ast, T>,
|
s: TypedFunctionSymbol<'ast, T>,
|
||||||
|
@ -805,10 +839,15 @@ pub fn fold_function_symbol<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
|
|
||||||
pub fn fold_module<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
pub fn fold_module<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
f: &mut F,
|
f: &mut F,
|
||||||
p: TypedModule<'ast, T>,
|
m: TypedModule<'ast, T>,
|
||||||
) -> Result<TypedModule<'ast, T>, F::Error> {
|
) -> Result<TypedModule<'ast, T>, F::Error> {
|
||||||
Ok(TypedModule {
|
Ok(TypedModule {
|
||||||
functions: p
|
constants: m
|
||||||
|
.constants
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, tc)| f.fold_constant_symbol(tc).map(|tc| (key, tc)))
|
||||||
|
.collect::<Result<_, _>>()?,
|
||||||
|
functions: m
|
||||||
.functions
|
.functions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(key, fun)| f.fold_function_symbol(fun).map(|f| (key, f)))
|
.map(|(key, fun)| f.fold_function_symbol(fun).map(|f| (key, f)))
|
||||||
|
|
16
zokrates_core_test/tests/tests/constants/array.json
Normal file
16
zokrates_core_test/tests/tests/constants/array.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/array.zok",
|
||||||
|
"max_constraint_count": 2,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["1", "2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
zokrates_core_test/tests/tests/constants/array.zok
Normal file
4
zokrates_core_test/tests/tests/constants/array.zok
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const field[2] ARRAY = [1, 2]
|
||||||
|
|
||||||
|
def main() -> field[2]:
|
||||||
|
return ARRAY
|
16
zokrates_core_test/tests/tests/constants/bool.json
Normal file
16
zokrates_core_test/tests/tests/constants/bool.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/bool.zok",
|
||||||
|
"max_constraint_count": 1,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
zokrates_core_test/tests/tests/constants/bool.zok
Normal file
4
zokrates_core_test/tests/tests/constants/bool.zok
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const bool BOOLEAN = true
|
||||||
|
|
||||||
|
def main() -> bool:
|
||||||
|
return BOOLEAN
|
16
zokrates_core_test/tests/tests/constants/field.json
Normal file
16
zokrates_core_test/tests/tests/constants/field.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/field.zok",
|
||||||
|
"max_constraint_count": 1,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
zokrates_core_test/tests/tests/constants/field.zok
Normal file
4
zokrates_core_test/tests/tests/constants/field.zok
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const field ONE = 1
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
return ONE
|
16
zokrates_core_test/tests/tests/constants/nested.json
Normal file
16
zokrates_core_test/tests/tests/constants/nested.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/nested.zok",
|
||||||
|
"max_constraint_count": 1,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["8"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
6
zokrates_core_test/tests/tests/constants/nested.zok
Normal file
6
zokrates_core_test/tests/tests/constants/nested.zok
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
const field A = 2
|
||||||
|
const field B = 2
|
||||||
|
const field[2] ARRAY = [A * 2, B * 2]
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
return ARRAY[0] + ARRAY[1]
|
16
zokrates_core_test/tests/tests/constants/struct.json
Normal file
16
zokrates_core_test/tests/tests/constants/struct.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/struct.zok",
|
||||||
|
"max_constraint_count": 1,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["4"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
9
zokrates_core_test/tests/tests/constants/struct.zok
Normal file
9
zokrates_core_test/tests/tests/constants/struct.zok
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
struct Foo {
|
||||||
|
field a
|
||||||
|
field b
|
||||||
|
}
|
||||||
|
|
||||||
|
const Foo FOO = Foo { a: 2, b: 2 }
|
||||||
|
|
||||||
|
def main() -> field:
|
||||||
|
return FOO.a + FOO.b
|
16
zokrates_core_test/tests/tests/constants/uint.json
Normal file
16
zokrates_core_test/tests/tests/constants/uint.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"entry_point": "./tests/tests/constants/uint.zok",
|
||||||
|
"max_constraint_count": 1,
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"input": {
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"Ok": {
|
||||||
|
"values": ["1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4
zokrates_core_test/tests/tests/constants/uint.zok
Normal file
4
zokrates_core_test/tests/tests/constants/uint.zok
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const u32 ONE = 0x00000001
|
||||||
|
|
||||||
|
def main() -> u32:
|
||||||
|
return ONE
|
|
@ -37,7 +37,7 @@ ace.define("ace/mode/zokrates_highlight_rules",["require","exports","module","ac
|
||||||
var ZoKratesHighlightRules = function () {
|
var ZoKratesHighlightRules = function () {
|
||||||
|
|
||||||
var keywords = (
|
var keywords = (
|
||||||
"assert|as|bool|byte|def|do|else|endfor|export|false|field|for|if|then|fi|import|from|in|private|public|return|struct|true|u8|u16|u32|u64"
|
"assert|as|bool|byte|const|def|do|else|endfor|export|false|field|for|if|then|fi|import|from|in|private|public|return|struct|true|u8|u16|u32|u64"
|
||||||
);
|
);
|
||||||
|
|
||||||
var keywordMapper = this.createKeywordMapper({
|
var keywordMapper = this.createKeywordMapper({
|
||||||
|
|
|
@ -1,27 +1,36 @@
|
||||||
{
|
{
|
||||||
"name": "zokrates",
|
"name": "zokrates",
|
||||||
"displayName": "zokrates",
|
"displayName": "zokrates",
|
||||||
"description": "Syntax highlighting for the ZoKrates language",
|
"description": "Syntax highlighting for the ZoKrates language",
|
||||||
"publisher": "zokrates",
|
"publisher": "zokrates",
|
||||||
"repository": "https://github.com/ZoKrates/ZoKrates",
|
"repository": "https://github.com/ZoKrates/ZoKrates",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.53.0"
|
"vscode": "^1.53.0"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Programming Languages"
|
"Programming Languages"
|
||||||
|
],
|
||||||
|
"contributes": {
|
||||||
|
"languages": [
|
||||||
|
{
|
||||||
|
"id": "zokrates",
|
||||||
|
"aliases": [
|
||||||
|
"ZoKrates",
|
||||||
|
"zokrates"
|
||||||
|
],
|
||||||
|
"extensions": [
|
||||||
|
".zok"
|
||||||
|
],
|
||||||
|
"configuration": "./language-configuration.json"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"contributes": {
|
"grammars": [
|
||||||
"languages": [{
|
{
|
||||||
"id": "zokrates",
|
"language": "zokrates",
|
||||||
"aliases": ["ZoKrates", "zokrates"],
|
"scopeName": "source.zok",
|
||||||
"extensions": [".zok"],
|
"path": "./syntaxes/zokrates.tmLanguage.json"
|
||||||
"configuration": "./language-configuration.json"
|
}
|
||||||
}],
|
]
|
||||||
"grammars": [{
|
}
|
||||||
"language": "zokrates",
|
|
||||||
"scopeName": "source.zok",
|
|
||||||
"path": "./syntaxes/zokrates.tmLanguage.json"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
349
zokrates_parser/src/textmate/zokrates.tmLanguage.yaml
Normal file
349
zokrates_parser/src/textmate/zokrates.tmLanguage.yaml
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
$schema: 'https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json'
|
||||||
|
name: ZoKrates
|
||||||
|
fileTypes:
|
||||||
|
- zok
|
||||||
|
scopeName: source.zok
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: attributes
|
||||||
|
name: meta.attribute.zokrates
|
||||||
|
begin: '(#)(\!?)(\[)'
|
||||||
|
beginCaptures:
|
||||||
|
'1':
|
||||||
|
name: punctuation.definition.attribute.zokrates
|
||||||
|
'2':
|
||||||
|
name: keyword.operator.attribute.inner.zokrates
|
||||||
|
'3':
|
||||||
|
name: punctuation.brackets.attribute.zokrates
|
||||||
|
end: '\]'
|
||||||
|
endCaptures:
|
||||||
|
'0':
|
||||||
|
name: punctuation.brackets.attribute.zokrates
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
include: '#block-comments'
|
||||||
|
-
|
||||||
|
include: '#comments'
|
||||||
|
-
|
||||||
|
include: '#keywords'
|
||||||
|
-
|
||||||
|
include: '#punctuation'
|
||||||
|
-
|
||||||
|
include: '#strings'
|
||||||
|
-
|
||||||
|
include: '#types'
|
||||||
|
-
|
||||||
|
include: '#block-comments'
|
||||||
|
-
|
||||||
|
include: '#comments'
|
||||||
|
-
|
||||||
|
include: '#constants'
|
||||||
|
-
|
||||||
|
include: '#functions'
|
||||||
|
-
|
||||||
|
include: '#types'
|
||||||
|
-
|
||||||
|
include: '#keywords'
|
||||||
|
-
|
||||||
|
include: '#punctuation'
|
||||||
|
-
|
||||||
|
include: '#strings'
|
||||||
|
-
|
||||||
|
include: '#variables'
|
||||||
|
repository:
|
||||||
|
comments:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'line comments'
|
||||||
|
name: comment.line.double-slash.zokrates
|
||||||
|
match: '\s*//.*'
|
||||||
|
block-comments:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'empty block comments'
|
||||||
|
name: comment.block.zokrates
|
||||||
|
match: '/\*\*/'
|
||||||
|
-
|
||||||
|
comment: 'block comments'
|
||||||
|
name: comment.block.zokrates
|
||||||
|
begin: '/\*(?!\*)'
|
||||||
|
end: '\*/'
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
constants:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'ALL CAPS constants'
|
||||||
|
name: constant.other.caps.zokrates
|
||||||
|
match: '\b[A-Z]{2}[A-Z0-9_]*\b'
|
||||||
|
-
|
||||||
|
comment: 'decimal integers and floats'
|
||||||
|
name: constant.numeric.decimal.zokrates
|
||||||
|
match: '\b\d[\d_]*(?:u128|u16|u32|u64|u8|f)?\b'
|
||||||
|
-
|
||||||
|
comment: 'hexadecimal integers'
|
||||||
|
name: constant.numeric.hex.zokrates
|
||||||
|
match: '\b0x[\da-fA-F_]+\b'
|
||||||
|
-
|
||||||
|
comment: booleans
|
||||||
|
name: constant.language.bool.zokrates
|
||||||
|
match: \b(true|false)\b
|
||||||
|
imports:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'explicit import statement'
|
||||||
|
name: meta.import.explicit.zokrates
|
||||||
|
match: '\b(from)\s+(\".*\")(import)\s+([A-Za-z0-9_]+)\s+((as)\s+[A-Za-z0-9_]+)?\b'
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#strings'}
|
||||||
|
-
|
||||||
|
comment: 'main import statement'
|
||||||
|
name: meta.import.explicit.zokrates
|
||||||
|
match: '\b(import)\s+(\".*\")\s+((as)\s+[A-Za-z0-9_]+)?\b'
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#strings'}
|
||||||
|
constant-definitions:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'constant definition'
|
||||||
|
name: meta.constant.definition.zokrates
|
||||||
|
match: '\b(const)\s+([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)\s+=\s+(?:.+)\b'
|
||||||
|
captures:
|
||||||
|
'1': {name: keyword.other.const.zokrates}
|
||||||
|
'2': {name: entity.name.type.zokrates}
|
||||||
|
'3': {name: entity.name.constant.zokrates}
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#constants'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#variables'}
|
||||||
|
functions:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'function definition'
|
||||||
|
name: meta.function.definition.zokrates
|
||||||
|
begin: '\b(def)\s+([A-Za-z0-9_]+)((\()|(<))'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: keyword.other.def.zokrates}
|
||||||
|
'2': {name: entity.name.function.zokrates}
|
||||||
|
'4': {name: punctuation.brackets.round.zokrates}
|
||||||
|
'5': {name: punctuation.brackets.angle.zokrates}
|
||||||
|
end: '\:|;'
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: keyword.punctuation.colon.zokrates}
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#constants'}
|
||||||
|
- {include: '#functions'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#strings'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#variables'}
|
||||||
|
-
|
||||||
|
comment: 'function/method calls, chaining'
|
||||||
|
name: meta.function.call.zokrates
|
||||||
|
begin: '([A-Za-z0-9_]+)(\()'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: entity.name.function.zokrates}
|
||||||
|
'2': {name: punctuation.brackets.round.zokrates}
|
||||||
|
end: \)
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.brackets.round.zokrates}
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#constants'}
|
||||||
|
- {include: '#functions'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#strings'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#variables'}
|
||||||
|
-
|
||||||
|
comment: 'function/method calls with turbofish'
|
||||||
|
name: meta.function.call.zokrates
|
||||||
|
begin: '([A-Za-z0-9_]+)(?=::<.*>\()'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: entity.name.function.zokrates}
|
||||||
|
end: \)
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.brackets.round.zokrates}
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#constants'}
|
||||||
|
- {include: '#functions'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#strings'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#variables'}
|
||||||
|
keywords:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'argument visibility'
|
||||||
|
name: keyword.visibility.zokrates
|
||||||
|
match: \b(public|private)\b
|
||||||
|
-
|
||||||
|
comment: 'control flow keywords'
|
||||||
|
name: keyword.control.zokrates
|
||||||
|
match: \b(do|else|for|do|endfor|if|then|fi|return|assert)\b
|
||||||
|
-
|
||||||
|
comment: 'storage keywords'
|
||||||
|
name: storage.type.zokrates
|
||||||
|
match: \b(struct)\b
|
||||||
|
-
|
||||||
|
comment: const
|
||||||
|
name: keyword.other.const.zokrates
|
||||||
|
match: \bconst\b
|
||||||
|
-
|
||||||
|
comment: def
|
||||||
|
name: keyword.other.def.zokrates
|
||||||
|
match: \bdef\b
|
||||||
|
-
|
||||||
|
comment: 'import keywords'
|
||||||
|
name: keyword.other.import.zokrates
|
||||||
|
match: \b(import|from|as)\b
|
||||||
|
-
|
||||||
|
comment: 'logical operators'
|
||||||
|
name: keyword.operator.logical.zokrates
|
||||||
|
match: '(\^|\||\|\||&|&&|<<|>>|!)(?!=)'
|
||||||
|
-
|
||||||
|
comment: 'single equal'
|
||||||
|
name: keyword.operator.assignment.equal.zokrates
|
||||||
|
match: '(?<![<>])=(?!=|>)'
|
||||||
|
-
|
||||||
|
comment: 'comparison operators'
|
||||||
|
name: keyword.operator.comparison.zokrates
|
||||||
|
match: '(=(=)?(?!>)|!=|<=|(?<!=)>=)'
|
||||||
|
-
|
||||||
|
comment: 'math operators'
|
||||||
|
name: keyword.operator.math.zokrates
|
||||||
|
match: '(([+%]|(\*(?!\w)))(?!=))|(-(?!>))|(/(?!/))'
|
||||||
|
-
|
||||||
|
comment: 'less than, greater than (special case)'
|
||||||
|
match: '(?:\b|(?:(\))|(\])|(\})))[ \t]+([<>])[ \t]+(?:\b|(?:(\()|(\[)|(\{)))'
|
||||||
|
captures:
|
||||||
|
'1': {name: punctuation.brackets.round.zokrates}
|
||||||
|
'2': {name: punctuation.brackets.square.zokrates}
|
||||||
|
'3': {name: punctuation.brackets.curly.zokrates}
|
||||||
|
'4': {name: keyword.operator.comparison.zokrates}
|
||||||
|
'5': {name: punctuation.brackets.round.zokrates}
|
||||||
|
'6': {name: punctuation.brackets.square.zokrates}
|
||||||
|
'7': {name: punctuation.brackets.curly.zokrates}
|
||||||
|
-
|
||||||
|
comment: 'dot access'
|
||||||
|
name: keyword.operator.access.dot.zokrates
|
||||||
|
match: '\.(?!\.)'
|
||||||
|
-
|
||||||
|
comment: 'ranges, range patterns'
|
||||||
|
name: keyword.operator.range.zokrates
|
||||||
|
match: '\.{2}(=|\.)?'
|
||||||
|
-
|
||||||
|
comment: colon
|
||||||
|
name: keyword.operator.colon.zokrates
|
||||||
|
match: ':(?!:)'
|
||||||
|
-
|
||||||
|
comment: 'dashrocket, skinny arrow'
|
||||||
|
name: keyword.operator.arrow.skinny.zokrates
|
||||||
|
match: '->'
|
||||||
|
types:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'numeric types'
|
||||||
|
match: '(?<![A-Za-z])(u128|u16|u32|u64|u8|field)\b'
|
||||||
|
captures:
|
||||||
|
'1': {name: entity.name.type.numeric.zokrates}
|
||||||
|
-
|
||||||
|
comment: 'parameterized types'
|
||||||
|
begin: '\b([A-Z][A-Za-z0-9]*)(<)'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: entity.name.type.zokrates}
|
||||||
|
'2': {name: punctuation.brackets.angle.zokrates}
|
||||||
|
end: '>'
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.brackets.angle.zokrates}
|
||||||
|
patterns:
|
||||||
|
- {include: '#block-comments'}
|
||||||
|
- {include: '#comments'}
|
||||||
|
- {include: '#keywords'}
|
||||||
|
- {include: '#punctuation'}
|
||||||
|
- {include: '#types'}
|
||||||
|
- {include: '#variables'}
|
||||||
|
-
|
||||||
|
comment: 'primitive types'
|
||||||
|
name: entity.name.type.primitive.zokrates
|
||||||
|
match: \b(bool)\b
|
||||||
|
-
|
||||||
|
comment: 'struct declarations'
|
||||||
|
match: '\b(struct)\s+([A-Z][A-Za-z0-9]*)\b'
|
||||||
|
captures:
|
||||||
|
'1': {name: storage.type.zokrates}
|
||||||
|
'2': {name: entity.name.type.struct.zokrates}
|
||||||
|
-
|
||||||
|
comment: types
|
||||||
|
name: entity.name.type.zokrates
|
||||||
|
match: '\b[A-Z][A-Za-z0-9]*\b(?!!)'
|
||||||
|
punctuation:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: comma
|
||||||
|
name: punctuation.comma.zokrates
|
||||||
|
match: ','
|
||||||
|
-
|
||||||
|
comment: 'parentheses, round brackets'
|
||||||
|
name: punctuation.brackets.round.zokrates
|
||||||
|
match: '[()]'
|
||||||
|
-
|
||||||
|
comment: 'square brackets'
|
||||||
|
name: punctuation.brackets.square.zokrates
|
||||||
|
match: '[\[\]]'
|
||||||
|
-
|
||||||
|
comment: 'angle brackets'
|
||||||
|
name: punctuation.brackets.angle.zokrates
|
||||||
|
match: '(?<!=)[<>]'
|
||||||
|
strings:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: 'double-quoted strings and byte strings'
|
||||||
|
name: string.quoted.double.zokrates
|
||||||
|
begin: '(b?)(")'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: string.quoted.byte.raw.zokrates}
|
||||||
|
'2': {name: punctuation.definition.string.zokrates}
|
||||||
|
end: '"'
|
||||||
|
endCaptures:
|
||||||
|
'0': {name: punctuation.definition.string.zokrates}
|
||||||
|
-
|
||||||
|
comment: 'double-quoted raw strings and raw byte strings'
|
||||||
|
name: string.quoted.double.zokrates
|
||||||
|
begin: '(b?r)(#*)(")'
|
||||||
|
beginCaptures:
|
||||||
|
'1': {name: string.quoted.byte.raw.zokrates}
|
||||||
|
'2': {name: punctuation.definition.string.raw.zokrates}
|
||||||
|
'3': {name: punctuation.definition.string.zokrates}
|
||||||
|
end: '(")(\2)'
|
||||||
|
endCaptures:
|
||||||
|
'1': {name: punctuation.definition.string.zokrates}
|
||||||
|
'2': {name: punctuation.definition.string.raw.zokrates}
|
||||||
|
variables:
|
||||||
|
patterns:
|
||||||
|
-
|
||||||
|
comment: variables
|
||||||
|
name: variable.other.zokrates
|
||||||
|
match: '\b(?<!(?<!\.)\.)[a-z0-9_]+\b'
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
file = { SOI ~ NEWLINE* ~ pragma? ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ ty_struct_definition* ~ NEWLINE* ~ function_definition* ~ EOI }
|
file = { SOI ~ NEWLINE* ~ pragma? ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ ty_struct_definition* ~ NEWLINE* ~ const_definition* ~ NEWLINE* ~ function_definition* ~ EOI }
|
||||||
|
|
||||||
pragma = { "#pragma" ~ "curve" ~ curve }
|
pragma = { "#pragma" ~ "curve" ~ curve }
|
||||||
curve = @{ (ASCII_ALPHANUMERIC | "_") * }
|
curve = @{ (ASCII_ALPHANUMERIC | "_") * }
|
||||||
|
@ -11,6 +11,7 @@ import_source = @{(!"\"" ~ ANY)*}
|
||||||
import_symbol = { identifier ~ ("as" ~ identifier)? }
|
import_symbol = { identifier ~ ("as" ~ identifier)? }
|
||||||
import_symbol_list = _{ import_symbol ~ ("," ~ import_symbol)* }
|
import_symbol_list = _{ import_symbol ~ ("," ~ import_symbol)* }
|
||||||
function_definition = {"def" ~ identifier ~ constant_generics_declaration? ~ "(" ~ parameter_list ~ ")" ~ return_types ~ ":" ~ NEWLINE* ~ statement* }
|
function_definition = {"def" ~ identifier ~ constant_generics_declaration? ~ "(" ~ parameter_list ~ ")" ~ return_types ~ ":" ~ NEWLINE* ~ statement* }
|
||||||
|
const_definition = {"const" ~ ty ~ identifier ~ "=" ~ expression ~ NEWLINE*}
|
||||||
return_types = _{ ( "->" ~ ( "(" ~ type_list ~ ")" | ty ))? }
|
return_types = _{ ( "->" ~ ( "(" ~ type_list ~ ")" | ty ))? }
|
||||||
constant_generics_declaration = _{ "<" ~ constant_generics_list ~ ">" }
|
constant_generics_declaration = _{ "<" ~ constant_generics_list ~ ">" }
|
||||||
constant_generics_list = _{ identifier ~ ("," ~ identifier)* }
|
constant_generics_list = _{ identifier ~ ("," ~ identifier)* }
|
||||||
|
@ -159,6 +160,6 @@ COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
||||||
|
|
||||||
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
|
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
|
||||||
// accepted
|
// accepted
|
||||||
keyword = @{"assert"|"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
|
keyword = @{"assert"|"as"|"bool"|"byte"|"const"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
|
||||||
"in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"|"u64"
|
"in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"|"u64"
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@ extern crate lazy_static;
|
||||||
pub use ast::{
|
pub use ast::{
|
||||||
Access, Arguments, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement,
|
Access, Arguments, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement,
|
||||||
Assignee, AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator,
|
Assignee, AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator,
|
||||||
CallAccess, ConstantGenericValue, DecimalLiteralExpression, DecimalNumber, DecimalSuffix,
|
CallAccess, ConstantDefinition, ConstantGenericValue, DecimalLiteralExpression, DecimalNumber,
|
||||||
DefinitionStatement, ExplicitGenerics, Expression, FieldType, File, FromExpression, Function,
|
DecimalSuffix, DefinitionStatement, ExplicitGenerics, Expression, FieldType, File,
|
||||||
HexLiteralExpression, HexNumberExpression, IdentifierExpression, ImportDirective, ImportSource,
|
FromExpression, Function, HexLiteralExpression, HexNumberExpression, IdentifierExpression,
|
||||||
ImportSymbol, InlineArrayExpression, InlineStructExpression, InlineStructMember,
|
ImportDirective, ImportSource, ImportSymbol, InlineArrayExpression, InlineStructExpression,
|
||||||
IterationStatement, LiteralExpression, OptionallyTypedAssignee, Parameter, PostfixExpression,
|
InlineStructMember, IterationStatement, LiteralExpression, OptionallyTypedAssignee, Parameter,
|
||||||
Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement,
|
PostfixExpression, Range, RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression,
|
||||||
StructDefinition, StructField, TernaryExpression, ToExpression, Type, UnaryExpression,
|
Statement, StructDefinition, StructField, TernaryExpression, ToExpression, Type,
|
||||||
UnaryOperator, Underscore, Visibility,
|
UnaryExpression, UnaryOperator, Underscore, Visibility,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod ast {
|
mod ast {
|
||||||
|
@ -111,6 +111,7 @@ mod ast {
|
||||||
pub pragma: Option<Pragma<'ast>>,
|
pub pragma: Option<Pragma<'ast>>,
|
||||||
pub imports: Vec<ImportDirective<'ast>>,
|
pub imports: Vec<ImportDirective<'ast>>,
|
||||||
pub structs: Vec<StructDefinition<'ast>>,
|
pub structs: Vec<StructDefinition<'ast>>,
|
||||||
|
pub constants: Vec<ConstantDefinition<'ast>>,
|
||||||
pub functions: Vec<Function<'ast>>,
|
pub functions: Vec<Function<'ast>>,
|
||||||
pub eoi: EOI,
|
pub eoi: EOI,
|
||||||
#[pest_ast(outer())]
|
#[pest_ast(outer())]
|
||||||
|
@ -164,6 +165,16 @@ mod ast {
|
||||||
pub span: Span<'ast>,
|
pub span: Span<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
|
#[pest_ast(rule(Rule::const_definition))]
|
||||||
|
pub struct ConstantDefinition<'ast> {
|
||||||
|
pub ty: Type<'ast>,
|
||||||
|
pub id: IdentifierExpression<'ast>,
|
||||||
|
pub expression: Expression<'ast>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
#[pest_ast(rule(Rule::import_directive))]
|
#[pest_ast(rule(Rule::import_directive))]
|
||||||
pub enum ImportDirective<'ast> {
|
pub enum ImportDirective<'ast> {
|
||||||
|
@ -1047,6 +1058,7 @@ mod tests {
|
||||||
Ok(File {
|
Ok(File {
|
||||||
pragma: None,
|
pragma: None,
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
|
constants: vec![],
|
||||||
functions: vec![Function {
|
functions: vec![Function {
|
||||||
generics: vec![],
|
generics: vec![],
|
||||||
id: IdentifierExpression {
|
id: IdentifierExpression {
|
||||||
|
@ -1107,6 +1119,7 @@ mod tests {
|
||||||
Ok(File {
|
Ok(File {
|
||||||
pragma: None,
|
pragma: None,
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
|
constants: vec![],
|
||||||
functions: vec![Function {
|
functions: vec![Function {
|
||||||
generics: vec![],
|
generics: vec![],
|
||||||
id: IdentifierExpression {
|
id: IdentifierExpression {
|
||||||
|
@ -1191,6 +1204,7 @@ mod tests {
|
||||||
Ok(File {
|
Ok(File {
|
||||||
pragma: None,
|
pragma: None,
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
|
constants: vec![],
|
||||||
functions: vec![Function {
|
functions: vec![Function {
|
||||||
generics: vec![],
|
generics: vec![],
|
||||||
id: IdentifierExpression {
|
id: IdentifierExpression {
|
||||||
|
@ -1259,6 +1273,7 @@ mod tests {
|
||||||
Ok(File {
|
Ok(File {
|
||||||
pragma: None,
|
pragma: None,
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
|
constants: vec![],
|
||||||
functions: vec![Function {
|
functions: vec![Function {
|
||||||
generics: vec![],
|
generics: vec![],
|
||||||
id: IdentifierExpression {
|
id: IdentifierExpression {
|
||||||
|
@ -1299,6 +1314,7 @@ mod tests {
|
||||||
Ok(File {
|
Ok(File {
|
||||||
pragma: None,
|
pragma: None,
|
||||||
structs: vec![],
|
structs: vec![],
|
||||||
|
constants: vec![],
|
||||||
functions: vec![Function {
|
functions: vec![Function {
|
||||||
generics: vec![],
|
generics: vec![],
|
||||||
id: IdentifierExpression {
|
id: IdentifierExpression {
|
||||||
|
|
Loading…
Reference in a new issue