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) 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) 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 namespace = None;
let mut use_statements = vec![];
let mut declarations = vec![]; let mut declarations = vec![];
for inner_pair in compilation_unit_pair.into_inner() { 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 => { Rule::Namespace => {
namespace = Some(build_namespace(file_id, inner_pair)); namespace = Some(build_namespace(file_id, inner_pair));
} }
Rule::UseStatement => {
use_statements.push(build_use_statement(file_id, inner_pair));
}
Rule::ModuleLevelDeclaration => { Rule::ModuleLevelDeclaration => {
declarations.push(build_module_level_declaration(file_id, inner_pair)); declarations.push(build_module_level_declaration(file_id, inner_pair));
} }
Rule::EOI => {} Rule::Semicolon | Rule::EOI => {}
_ => unreachable!(), _ => 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_name: file_name.to_string(),
file_id, file_id,
namespace, namespace,
use_statements,
declarations, 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 { fn build_block_statement(file_id: usize, block_statement_pair: Pair<Rule>) -> BlockStatement {
let mut statements = vec![]; let mut statements = vec![];
let mut expression = None; let mut expression = None;
@ -1690,7 +1750,7 @@ mod tests {
} }
"}) "})
} }
#[test] #[test]
fn if_with_call_condition() { fn if_with_call_condition() {
assert_builds(indoc! {" assert_builds(indoc! {"
@ -1701,7 +1761,7 @@ mod tests {
} }
"}) "})
} }
#[test] #[test]
fn while_with_call_condition() { fn while_with_call_condition() {
assert_builds(indoc! {" assert_builds(indoc! {"
@ -1712,7 +1772,7 @@ mod tests {
} }
"}) "})
} }
#[test] #[test]
fn for_with_call_iterator() { fn for_with_call_iterator() {
assert_builds(indoc! {" assert_builds(indoc! {"
@ -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_name: String,
pub file_id: usize, pub file_id: usize,
pub namespace: Option<FullyQualifiedName>, pub namespace: Option<FullyQualifiedName>,
pub use_statements: Vec<UseStatement>,
pub declarations: Vec<ModuleLevelDeclaration>, pub declarations: Vec<ModuleLevelDeclaration>,
} }
@ -450,6 +451,19 @@ pub struct FieldDeclaration {
// Statements // 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)] #[derive(Debug)]
pub struct BlockStatement { pub struct BlockStatement {
pub statements: Vec<Statement>, pub statements: Vec<Statement>,

View File

@ -282,6 +282,9 @@ impl PrettyPrint for CompilationUnit {
namespace.pretty_print(writer)?; namespace.pretty_print(writer)?;
writer.decrease_indent(); writer.decrease_indent();
} }
for use_statement in &self.use_statements {
use_statement.pretty_print(writer)?;
}
for declaration in &self.declarations { for declaration in &self.declarations {
declaration.pretty_print(writer)?; 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 { impl PrettyPrint for BlockStatement {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> { fn pretty_print(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("BlockStatement")?; writer.writeln_indented("BlockStatement")?;

View File

@ -373,7 +373,11 @@ impl Unparse for CompilationUnit {
if let Some(namespace) = &self.namespace { if let Some(namespace) = &self.namespace {
writer.write("ns ")?; writer.write("ns ")?;
namespace.unparse(writer)?; 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))?; unparse_list(writer, "\n\n", &to_unparse_vec!(self.declarations))?;
Ok(()) Ok(())
@ -722,6 +726,41 @@ impl Unparse for FieldDeclaration {
/* Statements */ /* 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 { impl Unparse for BlockStatement {
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> { fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
writer.writeln_indented("{")?; writer.writeln_indented("{")?;

View File

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

View File

@ -8,7 +8,7 @@ pub struct DeimosParser;
mod deimos_parser_tests { mod deimos_parser_tests {
use crate::parser::{DeimosParser, Rule}; use crate::parser::{DeimosParser, Rule};
use indoc::indoc; use indoc::indoc;
use pest::{parses_to, Parser}; use pest::Parser;
macro_rules! fail_rule { macro_rules! fail_rule {
($pair: expr; $rule:path) => {{ ($pair: expr; $rule:path) => {{
@ -147,37 +147,58 @@ mod deimos_parser_tests {
}"}, }"},
) )
} }
#[test] #[test]
fn while_statement() { fn while_statement() {
parses_to(Rule::WhileStatement, "while (foo) { bar() }"); parses_to(Rule::WhileStatement, "while (foo) { bar() }");
} }
#[test] #[test]
fn for_statement() { fn for_statement() {
parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }"); parses_to(Rule::ForStatement, "for (foo in bar) { baz(foo); }");
} }
#[test] #[test]
fn if_statement_with_call_condition() { fn if_statement_with_call_condition() {
parses_to(Rule::IfStatement, indoc! {" parses_to(
Rule::IfStatement,
indoc! {"
if (foo()) { if (foo()) {
bar() bar()
} }
"}) "},
)
} }
#[test] #[test]
fn while_statement_with_call_condition() { fn while_statement_with_call_condition() {
parses_to(Rule::WhileStatement, "while (foo()) { bar(); }") parses_to(Rule::WhileStatement, "while (foo()) { bar(); }")
} }
#[test] #[test]
fn for_statement_with_call_iterator() { fn for_statement_with_call_iterator() {
parses_to(Rule::ForStatement, indoc! {" parses_to(
Rule::ForStatement,
indoc! {"
for (foo in bar()) { for (foo in bar()) {
baz(foo); 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}");
} }
} }