Add use statements.

This commit is contained in:
Jesse Brault 2025-05-18 08:32:16 -05:00
parent 0c18b976d7
commit 938391ae09
7 changed files with 224 additions and 18 deletions

View File

@ -0,0 +1,3 @@
use std::core::println;
use std::core::*;
use std::core::{print, println};

View File

@ -15,7 +15,11 @@ fn expect_and_use<T>(
f(file_id, pair)
}
pub fn build_ast(file_name: &str, file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit {
pub fn build_ast(
file_name: &str,
file_id: usize,
compilation_unit_pair: Pair<Rule>,
) -> CompilationUnit {
build_compilation_unit(file_name, file_id, compilation_unit_pair)
}
@ -293,8 +297,13 @@ fn build_references(file_id: usize, ref_list_pair: Pair<Rule>) -> References {
)
}
fn build_compilation_unit(file_name: &str, file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit {
fn build_compilation_unit(
file_name: &str,
file_id: usize,
compilation_unit_pair: Pair<Rule>,
) -> CompilationUnit {
let mut namespace = None;
let mut use_statements = vec![];
let mut declarations = vec![];
for inner_pair in compilation_unit_pair.into_inner() {
@ -302,10 +311,13 @@ fn build_compilation_unit(file_name: &str, file_id: usize, compilation_unit_pair
Rule::Namespace => {
namespace = Some(build_namespace(file_id, inner_pair));
}
Rule::UseStatement => {
use_statements.push(build_use_statement(file_id, inner_pair));
}
Rule::ModuleLevelDeclaration => {
declarations.push(build_module_level_declaration(file_id, inner_pair));
}
Rule::EOI => {}
Rule::Semicolon | Rule::EOI => {}
_ => unreachable!(),
}
}
@ -314,6 +326,7 @@ fn build_compilation_unit(file_name: &str, file_id: usize, compilation_unit_pair
file_name: file_name.to_string(),
file_id,
namespace,
use_statements,
declarations,
}
}
@ -741,6 +754,53 @@ fn build_field_declaration(file_id: usize, field_pair: Pair<Rule>) -> FieldDecla
}
}
fn build_use_statement(file_id: usize, use_statement_pair: Pair<Rule>) -> UseStatement {
let mut inner = use_statement_pair.into_inner();
let inner_length = inner.len();
inner.next().unwrap(); // use
let mut identifiers = vec![];
let mut last = None;
for (i, inner_pair) in inner.into_iter().enumerate() {
if i != inner_length - 2 {
identifiers.push(expect_and_use(
file_id,
inner_pair,
Rule::Identifier,
build_identifier,
))
} else {
last = Some(match inner_pair.as_rule() {
Rule::Identifier => {
UseStatementLast::Identifier(build_identifier(file_id, inner_pair))
}
Rule::Star => UseStatementLast::Star,
Rule::UseList => UseStatementLast::Identifiers(
inner_pair
.into_inner()
.map(|identifier_pair| {
expect_and_use(
file_id,
identifier_pair,
Rule::Identifier,
build_identifier,
)
})
.collect(),
),
_ => unreachable!(),
})
}
}
UseStatement {
identifiers,
last: last.unwrap(),
}
}
fn build_block_statement(file_id: usize, block_statement_pair: Pair<Rule>) -> BlockStatement {
let mut statements = vec![];
let mut expression = None;
@ -1723,4 +1783,19 @@ mod tests {
}
"})
}
#[test]
fn use_statement() {
assert_builds("use std::core::println;");
}
#[test]
fn use_star() {
assert_builds("use std::core::*;");
}
#[test]
fn use_list() {
assert_builds("use std::core::{print, println};");
}
}

View File

@ -290,6 +290,7 @@ pub struct CompilationUnit {
pub file_name: String,
pub file_id: usize,
pub namespace: Option<FullyQualifiedName>,
pub use_statements: Vec<UseStatement>,
pub declarations: Vec<ModuleLevelDeclaration>,
}
@ -450,6 +451,19 @@ pub struct FieldDeclaration {
// Statements
#[derive(Debug)]
pub struct UseStatement {
pub identifiers: Vec<Identifier>,
pub last: UseStatementLast
}
#[derive(Debug)]
pub enum UseStatementLast {
Identifier(Identifier),
Identifiers(Vec<Identifier>),
Star,
}
#[derive(Debug)]
pub struct BlockStatement {
pub statements: Vec<Statement>,

View File

@ -282,6 +282,9 @@ impl PrettyPrint for CompilationUnit {
namespace.pretty_print(writer)?;
writer.decrease_indent();
}
for use_statement in &self.use_statements {
use_statement.pretty_print(writer)?;
}
for declaration in &self.declarations {
declaration.pretty_print(writer)?;
}
@ -585,6 +588,39 @@ impl PrettyPrint for FieldDeclaration {
}
}
impl PrettyPrint for UseStatement {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("UseStatement")?;
writer.increase_indent();
for identifier in &self.identifiers {
identifier.pretty_print(writer)?;
}
self.last.pretty_print(writer)?;
writer.decrease_indent();
Ok(())
}
}
impl PrettyPrint for UseStatementLast {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("UseStatementLast")?;
writer.increase_indent();
match self {
UseStatementLast::Identifier(i) => i.pretty_print(writer)?,
UseStatementLast::Identifiers(is) => {
for i in is {
i.pretty_print(writer)?;
}
},
UseStatementLast::Star => {
writer.writeln_indented("Star")?;
}
}
writer.decrease_indent();
Ok(())
}
}
impl PrettyPrint for BlockStatement {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("BlockStatement")?;

View File

@ -373,7 +373,11 @@ impl Unparse for CompilationUnit {
if let Some(namespace) = &self.namespace {
writer.write("ns ")?;
namespace.unparse(writer)?;
writer.write("\n\n")?;
writer.write(";\n\n")?;
}
for use_statement in &self.use_statements {
use_statement.unparse(writer)?;
writer.write(";\n")?;
}
unparse_list(writer, "\n\n", &to_unparse_vec!(self.declarations))?;
Ok(())
@ -722,6 +726,41 @@ impl Unparse for FieldDeclaration {
/* Statements */
impl Unparse for UseStatement {
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.write_indented("use ")?;
for (i, identifier) in self.identifiers.iter().enumerate() {
identifier.unparse(writer)?;
if i != self.identifiers.len() - 2 {
// 2 because of use
writer.write("::")?;
}
}
self.last.unparse(writer)?;
Ok(())
}
}
impl Unparse for UseStatementLast {
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
match self {
UseStatementLast::Star => writer.write("*"),
UseStatementLast::Identifiers(identifiers) => {
writer.write("{")?;
for (i, identifier) in identifiers.iter().enumerate() {
identifier.unparse(writer)?;
if i != identifiers.len() - 1 {
writer.write(", ")?;
}
}
writer.write("}")?;
Ok(())
}
UseStatementLast::Identifier(i) => i.unparse(writer),
}
}
}
impl Unparse for BlockStatement {
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("{")?;

View File

@ -30,6 +30,7 @@ Move = { "move" }
Alias = { "alias" }
True = { "true" }
False = { "false" }
Use = { "use" }
// Keywords as a rule (for preventing identifiers with keywords, etc.)
Keyword = {
@ -64,6 +65,7 @@ Keyword = {
| Alias
| True
| False
| Use
}
// Symbols
@ -280,7 +282,8 @@ RefList = {
CompilationUnit = {
SOI
~ Namespace?
~ ( Namespace ~ Semicolon )?
~ ( UseStatement ~ Semicolon )*
~ ModuleLevelDeclaration*
~ EOI
}
@ -479,6 +482,20 @@ Field = {
// Statements
UseStatement = {
Use
~ Identifier
~ ( "::" ~ Identifier )*
~ ( "::" ~ ( Star | UseList ) )?
}
UseList = {
"{"
~ Identifier
~ ( "," ~ Identifier )*
~ "}"
}
BlockStatement = {
"{"
~ Statement*
@ -492,6 +509,7 @@ Statement = {
| AssignmentStatement
| CallStatement
| ReturnStatement
| UseStatement
)
~ Semicolon
| (

View File

@ -8,7 +8,7 @@ pub struct DeimosParser;
mod deimos_parser_tests {
use crate::parser::{DeimosParser, Rule};
use indoc::indoc;
use pest::{parses_to, Parser};
use pest::Parser;
macro_rules! fail_rule {
($pair: expr; $rule:path) => {{
@ -160,11 +160,14 @@ mod deimos_parser_tests {
#[test]
fn if_statement_with_call_condition() {
parses_to(Rule::IfStatement, indoc! {"
parses_to(
Rule::IfStatement,
indoc! {"
if (foo()) {
bar()
}
"})
"},
)
}
#[test]
@ -174,10 +177,28 @@ mod deimos_parser_tests {
#[test]
fn for_statement_with_call_iterator() {
parses_to(Rule::ForStatement, indoc! {"
parses_to(
Rule::ForStatement,
indoc! {"
for (foo in bar()) {
baz(foo);
}
"})
"},
)
}
#[test]
fn use_statement() {
parses_to(Rule::UseStatement, "use std::core::println");
}
#[test]
fn use_star() {
parses_to(Rule::UseStatement, "use std::core::*")
}
#[test]
fn use_list() {
parses_to(Rule::UseStatement, "use std::core::{print, println}");
}
}