620: Feature/254 strengthen import rules r=collinc97 a=gluax

Grammar changes are a bit different than what was suggested in the original feature request #254. However, it should be logically equivalent and I think makes more sense on the rust side.

Closes #254 

Co-authored-by: gluaxspeed <jonathan.t.pavlik@gmail.com>
This commit is contained in:
bors[bot] 2021-02-11 07:31:56 +00:00 committed by GitHub
commit b72b5ac125
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 364 additions and 35 deletions

View File

@ -25,7 +25,7 @@ mod function;
pub use function::*; pub use function::*;
use crate::{AsgConvertError, ImportResolver, InnerScope, Input, Scope}; use crate::{AsgConvertError, ImportResolver, InnerScope, Input, Scope};
use leo_ast::{Identifier, Package, PackageAccess, Span}; use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span};
use indexmap::IndexMap; use indexmap::IndexMap;
use std::{cell::RefCell, sync::Arc}; use std::{cell::RefCell, sync::Arc};
@ -74,16 +74,25 @@ enum ImportSymbol {
fn resolve_import_package( fn resolve_import_package(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>, output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>, mut package_segments: Vec<String>,
package: &Package, package_or_packages: &PackageOrPackages,
) { ) {
package_segments.push(package.name.name.clone()); match package_or_packages {
PackageOrPackages::Package(package) => {
resolve_import_package_access(output, package_segments, &package.access); package_segments.push(package.name.name.clone());
resolve_import_package_access(output, package_segments, &package.access);
}
PackageOrPackages::Packages(packages) => {
package_segments.push(packages.name.name.clone());
for access in packages.accesses.clone() {
resolve_import_package_access(output, package_segments.clone(), &access);
}
}
}
} }
fn resolve_import_package_access( fn resolve_import_package_access(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>, output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
package_segments: Vec<String>, mut package_segments: Vec<String>,
package: &PackageAccess, package: &PackageAccess,
) { ) {
match package { match package {
@ -91,7 +100,11 @@ fn resolve_import_package_access(
output.push((package_segments, ImportSymbol::All, span.clone())); output.push((package_segments, ImportSymbol::All, span.clone()));
} }
PackageAccess::SubPackage(subpackage) => { PackageAccess::SubPackage(subpackage) => {
resolve_import_package(output, package_segments, &*subpackage); resolve_import_package(
output,
package_segments,
&PackageOrPackages::Package(*(*subpackage).clone()),
);
} }
PackageAccess::Symbol(symbol) => { PackageAccess::Symbol(symbol) => {
let span = symbol.symbol.span.clone(); let span = symbol.symbol.span.clone();
@ -102,8 +115,9 @@ fn resolve_import_package_access(
}; };
output.push((package_segments, symbol, span)); output.push((package_segments, symbol, span));
} }
PackageAccess::Multiple(subaccesses) => { PackageAccess::Multiple(packages) => {
for subaccess in subaccesses.iter() { package_segments.push(packages.name.name.clone());
for subaccess in packages.accesses.iter() {
resolve_import_package_access(output, package_segments.clone(), &subaccess); resolve_import_package_access(output, package_segments.clone(), &subaccess);
} }
} }
@ -126,7 +140,7 @@ impl InternalProgram {
// Recursively extract imported symbols. // Recursively extract imported symbols.
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![]; let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
for import in program.imports.iter() { for import in program.imports.iter() {
resolve_import_package(&mut imported_symbols, vec![], &import.package); resolve_import_package(&mut imported_symbols, vec![], &import.package_or_packages);
} }
// Create package list. // Create package list.
@ -383,11 +397,11 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program {
imports: core_programs imports: core_programs
.iter() .iter()
.map(|(module, _)| leo_ast::ImportStatement { .map(|(module, _)| leo_ast::ImportStatement {
package: leo_ast::Package { package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package {
name: Identifier::new(module.clone()), name: Identifier::new(module.clone()),
access: leo_ast::PackageAccess::Star(Span::default()), access: leo_ast::PackageAccess::Star(Span::default()),
span: Default::default(), span: Default::default(),
}, }),
span: Span::default(), span: Span::default(),
}) })
.collect(), .collect(),

View File

@ -1,3 +1,7 @@
circuit Baz { circuit Baz {
z: u32 z: u32
}
circuit Bazzar {
a: u32
} }

View File

@ -5,7 +5,7 @@ import test-import.( // local import
import bar.( // imports directory import import bar.( // imports directory import
Bar, Bar,
baz.Baz, baz.(Baz, Bazzar),
bat.bat.Bat, bat.bat.Bat,
); );
@ -17,6 +17,7 @@ function main() {
const bar = Bar { r: 1u32 }; const bar = Bar { r: 1u32 };
const baz = Baz { z: 1u32 }; const baz = Baz { z: 1u32 };
const bazzar = Bazzar { a: 1u32 };
const bat = Bat { t: 1u32 }; const bat = Bat { t: 1u32 };
const car = Car { c: 1u32 }; const car = Car { c: 1u32 };

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Package, Span}; use crate::{PackageOrPackages, Span};
use leo_grammar::imports::Import as GrammarImport; use leo_grammar::imports::Import as GrammarImport;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -23,7 +23,7 @@ use std::fmt;
/// Represents an import statement in a Leo program. /// Represents an import statement in a Leo program.
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct ImportStatement { pub struct ImportStatement {
pub package: Package, pub package_or_packages: PackageOrPackages,
pub span: Span, pub span: Span,
} }
@ -32,14 +32,17 @@ impl ImportStatement {
/// Returns the the package file name of the self import statement. /// Returns the the package file name of the self import statement.
/// ///
pub fn get_file_name(&self) -> &str { pub fn get_file_name(&self) -> &str {
&self.package.name.name match self.package_or_packages {
PackageOrPackages::Package(ref package) => &package.name.name,
PackageOrPackages::Packages(ref packages) => &packages.name.name,
}
} }
} }
impl<'ast> From<GrammarImport<'ast>> for ImportStatement { impl<'ast> From<GrammarImport<'ast>> for ImportStatement {
fn from(import: GrammarImport<'ast>) -> Self { fn from(import: GrammarImport<'ast>) -> Self {
ImportStatement { ImportStatement {
package: Package::from(import.package), package_or_packages: PackageOrPackages::from(import.package_or_packages),
span: Span::from(import.span), span: Span::from(import.span),
} }
} }
@ -47,7 +50,7 @@ impl<'ast> From<GrammarImport<'ast>> for ImportStatement {
impl ImportStatement { impl ImportStatement {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "import {};", self.package) write!(f, "import {};", self.package_or_packages)
} }
} }

View File

@ -23,5 +23,11 @@ pub use import_symbol::*;
pub mod package; pub mod package;
pub use package::*; pub use package::*;
pub mod packages;
pub use packages::*;
pub mod package_or_packages;
pub use package_or_packages::*;
pub mod package_access; pub mod package_access;
pub use package_access::*; pub use package_access::*;

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ImportSymbol, Package, Span}; use crate::{ImportSymbol, Package, Packages, Span};
use leo_grammar::imports::PackageAccess as GrammarPackageAccess; use leo_grammar::imports::PackageAccess as GrammarPackageAccess;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -25,7 +25,7 @@ pub enum PackageAccess {
Star(Span), Star(Span),
SubPackage(Box<Package>), SubPackage(Box<Package>),
Symbol(ImportSymbol), Symbol(ImportSymbol),
Multiple(Vec<PackageAccess>), Multiple(Packages),
} }
impl<'ast> From<GrammarPackageAccess<'ast>> for PackageAccess { impl<'ast> From<GrammarPackageAccess<'ast>> for PackageAccess {
@ -34,9 +34,7 @@ impl<'ast> From<GrammarPackageAccess<'ast>> for PackageAccess {
GrammarPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)), GrammarPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)),
GrammarPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))), GrammarPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))),
GrammarPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)), GrammarPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)),
GrammarPackageAccess::Multiple(accesses) => { GrammarPackageAccess::Multiple(packages) => PackageAccess::Multiple(Packages::from(packages)),
PackageAccess::Multiple(accesses.into_iter().map(PackageAccess::from).collect())
}
} }
} }
} }
@ -47,11 +45,11 @@ impl PackageAccess {
PackageAccess::Star(ref _span) => write!(f, "*"), PackageAccess::Star(ref _span) => write!(f, "*"),
PackageAccess::SubPackage(ref package) => write!(f, "{}", package), PackageAccess::SubPackage(ref package) => write!(f, "{}", package),
PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol), PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol),
PackageAccess::Multiple(ref accesses) => { PackageAccess::Multiple(ref packages) => {
write!(f, "(")?; write!(f, "(")?;
for (i, access) in accesses.iter().enumerate() { for (i, access) in packages.accesses.iter().enumerate() {
write!(f, "{}", access)?; write!(f, "{}", access)?;
if i < accesses.len() - 1 { if i < packages.accesses.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
} }
} }

View File

@ -0,0 +1,66 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Package, Packages};
use leo_grammar::imports::PackageOrPackages as GrammarPackageOrPackages;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum PackageOrPackages {
Package(Package),
Packages(Packages),
}
impl<'ast> From<GrammarPackageOrPackages<'ast>> for PackageOrPackages {
fn from(package_or_packages: GrammarPackageOrPackages<'ast>) -> Self {
match package_or_packages {
GrammarPackageOrPackages::Package(package) => PackageOrPackages::Package(Package::from(package)),
GrammarPackageOrPackages::Packages(packages) => PackageOrPackages::Packages(Packages::from(packages)),
}
}
}
impl PackageOrPackages {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PackageOrPackages::Package(ref package) => write!(f, "{}", package),
PackageOrPackages::Packages(ref packages) => {
write!(f, "(")?;
for (i, access) in packages.accesses.iter().enumerate() {
write!(f, "{}", access)?;
if i < packages.accesses.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
}
}
impl fmt::Debug for PackageOrPackages {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Display for PackageOrPackages {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}

View File

@ -0,0 +1,63 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{common::Identifier, PackageAccess, Span};
use leo_grammar::imports::Packages as GrammarPackages;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Packages {
pub name: Identifier,
pub accesses: Vec<PackageAccess>,
pub span: Span,
}
impl<'ast> From<GrammarPackages<'ast>> for Packages {
fn from(packages: GrammarPackages<'ast>) -> Self {
Packages {
name: Identifier::from(packages.name),
accesses: packages.accesses.into_iter().map(PackageAccess::from).collect(),
span: Span::from(packages.span),
}
}
}
impl Packages {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.(", self.name)?;
for (i, access) in self.accesses.iter().enumerate() {
write!(f, "{}", access)?;
if i < self.accesses.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
impl fmt::Display for Packages {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for Packages {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}

View File

@ -1,3 +1,7 @@
circuit Baz { circuit Baz {
z: u32 z: u32
}
circuit Bazzar {
a: u32
} }

View File

@ -5,7 +5,7 @@ import test-import.( // local import
import bar.( // imports directory import import bar.( // imports directory import
Bar, Bar,
baz.Baz, baz.(Baz, Bazzar),
bat.bat.Bat, bat.bat.Bat,
); );
@ -17,6 +17,7 @@ function main() {
const bar = Bar { r: 1u32 }; const bar = Bar { r: 1u32 };
const baz = Baz { z: 1u32 }; const baz = Baz { z: 1u32 };
const bazzar = Bazzar { a: 1u32 };
const bat = Bat { t: 1u32 }; const bat = Bat { t: 1u32 };
const car = Car { c: 1u32 }; const car = Car { c: 1u32 };

View File

@ -7,7 +7,7 @@ circuit PedersenHash {
} }
function hash(self, bits: [bool; 256]) -> group { function hash(self, bits: [bool; 256]) -> group {
let mut digest: group = 0; let mut digest: group = 0group;
for i in 0..256 { for i in 0..256 {
if bits[i] { if bits[i] {
digest += self.parameters[i]; digest += self.parameters[i];

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ast::Rule, common::LineEnd, imports::Package, SpanDef}; use crate::{ast::Rule, common::LineEnd, imports::PackageOrPackages, SpanDef};
use pest::Span; use pest::Span;
use pest_ast::FromPest; use pest_ast::FromPest;
@ -23,7 +23,7 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::import))] #[pest_ast(rule(Rule::import))]
pub struct Import<'ast> { pub struct Import<'ast> {
pub package: Package<'ast>, pub package_or_packages: PackageOrPackages<'ast>,
pub line_end: LineEnd, pub line_end: LineEnd,
#[pest_ast(outer())] #[pest_ast(outer())]
#[serde(with = "SpanDef")] #[serde(with = "SpanDef")]

View File

@ -23,6 +23,12 @@ pub use import_symbol::*;
pub mod package; pub mod package;
pub use package::*; pub use package::*;
pub mod packages;
pub use packages::*;
pub mod package_or_packages;
pub use package_or_packages::*;
pub mod package_access; pub mod package_access;
pub use package_access::*; pub use package_access::*;

View File

@ -16,7 +16,7 @@
use crate::{ use crate::{
ast::Rule, ast::Rule,
imports::{ImportSymbol, Package, Star}, imports::{ImportSymbol, Package, Packages, Star},
}; };
use pest_ast::FromPest; use pest_ast::FromPest;
@ -28,5 +28,5 @@ pub enum PackageAccess<'ast> {
Star(Star<'ast>), Star(Star<'ast>),
SubPackage(Box<Package<'ast>>), SubPackage(Box<Package<'ast>>),
Symbol(ImportSymbol<'ast>), Symbol(ImportSymbol<'ast>),
Multiple(Vec<PackageAccess<'ast>>), Multiple(Packages<'ast>),
} }

View File

@ -0,0 +1,30 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{
ast::Rule,
imports::{Package, Packages},
};
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::package_or_packages))]
pub enum PackageOrPackages<'ast> {
Package(Package<'ast>),
Packages(Packages<'ast>),
}

View File

@ -0,0 +1,35 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{
ast::Rule,
imports::{PackageAccess, PackageName},
SpanDef,
};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::packages))]
pub struct Packages<'ast> {
pub name: PackageName<'ast>,
pub accesses: Vec<PackageAccess<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -461,18 +461,25 @@ input_tuple = _{ "(" ~ (input ~ ("," ~ input)* ~ ","?)? ~ ")"}
/// Imports /// Imports
// Declared in imports/import.rs // Declared in imports/import.rs
import = { "import " ~ package ~ LINE_END} import = { "import " ~ package_or_packages ~ LINE_END}
// Declared in imports/package_name.rs // Declared in imports/package_name.rs
package_name = @{ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+ ~ ( "-" ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+)* } package_name = @{ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+ ~ ( "-" ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+)* }
// Declared in imports/package_or_packages.rs
package_or_packages = {
packages
| package
}
// Declared in imports/package.rs // Declared in imports/package.rs
package = { package_name ~ "." ~ package_access } package = { package_name ~ "." ~ package_access }
// Declared in imports/packages.rs
packages = { package_name ~ "." ~ multiple_package_access }
// Declared in imports/package_access // Declared in imports/package_access
package_access = { package_access = {
multiple_package_access star
| star | packages
| package // subpackage | package // subpackage
| import_symbol | import_symbol
} }

91
grammar/tests/imports.rs Normal file
View File

@ -0,0 +1,91 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_grammar::ast::{LanguageParser, Rule};
use pest::*;
#[test]
fn test_import_package_rule() {
parses_to! {
parser: LanguageParser,
input: "import p.*;",
rule: Rule::import,
tokens: [
import(0, 11, [
package_or_packages(7, 10, [
package(7, 10, [
package_name(7, 8, []),
package_access(9, 10, [star(9, 10, [])])
])
]),
LINE_END(10, 11, [])
]),
]
}
}
#[test]
fn test_import_packages_rule() {
parses_to! {
parser: LanguageParser,
input: "import p.(x, y);",
rule: Rule::import,
tokens: [
import(0, 16, [
package_or_packages(7, 15, [
packages(7, 15, [
package_name(7, 8, []),
package_access(10, 11, [
import_symbol(10, 11, [identifier(10, 11, [])]),
]),
package_access(13, 14, [
import_symbol(13, 14, [identifier(13, 14, [])]),
]),
])
]),
LINE_END(15, 16, [])
])
]
}
}
#[test]
fn test_complex_import_rule() {
parses_to! {
parser: LanguageParser,
input: "import p.(q.(x, y), z);",
rule: Rule::import,
tokens: [
import(0, 23, [
package_or_packages(7, 22, [
packages(7, 22, [
package_name(7, 8, []),
package_access(10, 18, [
packages(10, 18, [
package_name(10, 11, []),
package_access(13, 14, [import_symbol(13, 14, [identifier(13, 14, [])])]),
package_access(16, 17, [import_symbol(16, 17, [identifier(16, 17, [])])]),
]),
]),
package_access(20, 21, [import_symbol(20, 21, [identifier(20, 21, [])])]),
])
]),
LINE_END(22, 23, [])
])
]
}
}