Compare commits
8 Commits
3026d22750
...
c606432be2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c606432be2 | ||
![]() |
6b6ba1d712 | ||
![]() |
dcb261fd84 | ||
![]() |
4f74136d97 | ||
![]() |
8cd5e588a0 | ||
![]() |
c54e005b62 | ||
![]() |
938391ae09 | ||
![]() |
0c18b976d7 |
5
sketching/may_2025/print.dm
Normal file
5
sketching/may_2025/print.dm
Normal file
@ -0,0 +1,5 @@
|
||||
ns std::core;
|
||||
|
||||
platform fn print(msg: Any) -> Void;
|
||||
|
||||
platform fn println(msg: Any) -> Void;
|
3
sketching/may_2025/use.dm
Normal file
3
sketching/may_2025/use.dm
Normal file
@ -0,0 +1,3 @@
|
||||
use std::core::println;
|
||||
use std::core::*;
|
||||
use std::core::{print, println};
|
139
src/ast/build.rs
139
src/ast/build.rs
@ -15,8 +15,12 @@ fn expect_and_use<T>(
|
||||
f(file_id, pair)
|
||||
}
|
||||
|
||||
pub fn build_ast(file_id: usize, compilation_unit_pair: Pair<Rule>) -> CompilationUnit {
|
||||
build_compilation_unit(file_id, compilation_unit_pair)
|
||||
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)
|
||||
}
|
||||
|
||||
fn build_identifier(file_id: usize, identifier_pair: Pair<Rule>) -> Identifier {
|
||||
@ -293,8 +297,13 @@ fn build_references(file_id: usize, ref_list_pair: Pair<Rule>) -> References {
|
||||
)
|
||||
}
|
||||
|
||||
fn build_compilation_unit(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,16 +311,22 @@ fn build_compilation_unit(file_id: usize, compilation_unit_pair: Pair<Rule>) ->
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
||||
CompilationUnit {
|
||||
file_name: file_name.to_string(),
|
||||
file_id,
|
||||
namespace,
|
||||
use_statements,
|
||||
declarations,
|
||||
}
|
||||
}
|
||||
@ -579,7 +594,46 @@ fn build_platform_function_declaration(
|
||||
file_id: usize,
|
||||
platform_function_pair: Pair<Rule>,
|
||||
) -> PlatformFunctionDeclaration {
|
||||
todo!()
|
||||
let mut is_public = false;
|
||||
let mut modifier = None;
|
||||
let mut generics = GenericParameters::default();
|
||||
let mut identifier = None;
|
||||
let mut parameters = Parameters::default();
|
||||
let mut return_type = None;
|
||||
|
||||
for inner_pair in platform_function_pair.into_inner() {
|
||||
match inner_pair.as_rule() {
|
||||
Rule::Pub => {
|
||||
is_public = true;
|
||||
}
|
||||
Rule::FunctionModifier => {
|
||||
modifier = Some(build_function_modifier(file_id, inner_pair));
|
||||
}
|
||||
Rule::Platform | Rule::Fn => {}
|
||||
Rule::GenericParameters => {
|
||||
generics = build_generic_parameters(file_id, inner_pair);
|
||||
}
|
||||
Rule::Identifier => {
|
||||
identifier = Some(build_identifier(file_id, inner_pair));
|
||||
}
|
||||
Rule::Parameters => {
|
||||
parameters = build_parameters(file_id, inner_pair);
|
||||
}
|
||||
Rule::ReturnType => {
|
||||
return_type = Some(build_return_type(file_id, inner_pair));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
PlatformFunctionDeclaration {
|
||||
is_public,
|
||||
modifier,
|
||||
generics,
|
||||
identifier: identifier.unwrap(),
|
||||
parameters,
|
||||
return_type: return_type.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_interface_function_declaration(
|
||||
@ -739,6 +793,59 @@ 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 as_span = use_statement_pair.as_span();
|
||||
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(Rc::new(RefCell::new(
|
||||
build_identifier(file_id, inner_pair),
|
||||
))),
|
||||
Rule::Star => UseStatementLast::Star,
|
||||
Rule::UseList => UseStatementLast::Identifiers(
|
||||
inner_pair
|
||||
.into_inner()
|
||||
.map(|identifier_pair| {
|
||||
Rc::new(RefCell::new(expect_and_use(
|
||||
file_id,
|
||||
identifier_pair,
|
||||
Rule::Identifier,
|
||||
build_identifier,
|
||||
)))
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
UseStatement::new(
|
||||
identifiers,
|
||||
last.unwrap(),
|
||||
file_id,
|
||||
Range {
|
||||
start: as_span.start(),
|
||||
end: as_span.end(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn build_block_statement(file_id: usize, block_statement_pair: Pair<Rule>) -> BlockStatement {
|
||||
let mut statements = vec![];
|
||||
let mut expression = None;
|
||||
@ -1558,7 +1665,7 @@ mod tests {
|
||||
if pairs.as_str().trim() != src.trim() {
|
||||
panic!("Parsing did not consume entire input.");
|
||||
}
|
||||
let ast = build_ast(0, pairs.next().unwrap());
|
||||
let ast = build_ast("test.dm", 0, pairs.next().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1721,4 +1828,24 @@ 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};");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_function() {
|
||||
assert_builds("platform fn println(msg: Any) -> Void;");
|
||||
}
|
||||
}
|
||||
|
100
src/ast/mod.rs
100
src/ast/mod.rs
@ -1,6 +1,10 @@
|
||||
use crate::ast::named::Named;
|
||||
use crate::name_analysis::symbol::Symbol;
|
||||
use pest::Parser;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::range::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod build;
|
||||
pub mod named;
|
||||
@ -87,6 +91,10 @@ impl Identifier {
|
||||
pub fn symbol(&self) -> &Option<Symbol> {
|
||||
&self.symbol
|
||||
}
|
||||
|
||||
pub fn symbol_mut(&mut self) -> Option<Symbol> {
|
||||
self.symbol.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -287,7 +295,10 @@ impl Default for References {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompilationUnit {
|
||||
pub file_name: String,
|
||||
pub file_id: usize,
|
||||
pub namespace: Option<FullyQualifiedName>,
|
||||
pub use_statements: Vec<UseStatement>,
|
||||
pub declarations: Vec<ModuleLevelDeclaration>,
|
||||
}
|
||||
|
||||
@ -448,6 +459,91 @@ pub struct FieldDeclaration {
|
||||
|
||||
// Statements
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UseStatement {
|
||||
pub identifiers: Vec<Identifier>,
|
||||
pub last: UseStatementLast,
|
||||
pub file_id: usize,
|
||||
pub range: Range<usize>,
|
||||
scope_id: Option<usize>,
|
||||
symbol: Option<Symbol>,
|
||||
}
|
||||
|
||||
pub struct UseStatementImport<'a> {
|
||||
pub declared_name: String,
|
||||
pub fqn: String,
|
||||
pub identifier: &'a mut Identifier,
|
||||
}
|
||||
|
||||
impl UseStatement {
|
||||
pub fn new(
|
||||
identifiers: Vec<Identifier>,
|
||||
last: UseStatementLast,
|
||||
file_id: usize,
|
||||
range: Range<usize>,
|
||||
) -> Self {
|
||||
UseStatement {
|
||||
identifiers,
|
||||
last,
|
||||
file_id,
|
||||
range,
|
||||
scope_id: None,
|
||||
symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_name(&self) -> Cow<'_, str> {
|
||||
use UseStatementLast::*;
|
||||
if self.identifiers.is_empty() {
|
||||
match &self.last {
|
||||
Identifier(_) => Cow::from(""),
|
||||
Star | Identifiers(_) => panic!(), // should never get here because of grammar
|
||||
}
|
||||
} else if self.identifiers.len() == 1 {
|
||||
self.identifiers[0].name()
|
||||
} else {
|
||||
let mut acc = String::new();
|
||||
for (i, identifier) in self.identifiers.iter().enumerate() {
|
||||
acc.push_str(&identifier.name());
|
||||
if i != self.identifiers.len() - 1 {
|
||||
acc.push_str("::");
|
||||
}
|
||||
}
|
||||
Cow::from(acc)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_star(&self) -> bool {
|
||||
match &self.last {
|
||||
UseStatementLast::Star => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_scope_id(&mut self, scope_id: usize) {
|
||||
self.scope_id = Some(scope_id);
|
||||
}
|
||||
|
||||
pub fn scope_id(&self) -> Option<usize> {
|
||||
self.scope_id
|
||||
}
|
||||
|
||||
pub fn set_symbol(&mut self, symbol: Symbol) {
|
||||
self.symbol = Some(symbol);
|
||||
}
|
||||
|
||||
pub fn symbol(&self) -> &Option<Symbol> {
|
||||
&self.symbol
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UseStatementLast {
|
||||
Identifier(Rc<RefCell<Identifier>>),
|
||||
Identifiers(Vec<Rc<RefCell<Identifier>>>),
|
||||
Star,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlockStatement {
|
||||
pub statements: Vec<Statement>,
|
||||
@ -556,8 +652,8 @@ pub struct PrefixExpression {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SuffixExpression {
|
||||
expression: Box<Expression>,
|
||||
operator: SuffixUnaryOperator,
|
||||
pub expression: Box<Expression>,
|
||||
pub operator: SuffixUnaryOperator,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -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.borrow().pretty_print(writer)?,
|
||||
UseStatementLast::Identifiers(is) => {
|
||||
for i in is {
|
||||
i.borrow().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")?;
|
||||
|
@ -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(())
|
||||
@ -570,6 +574,7 @@ impl Unparse for PlatformFunctionDeclaration {
|
||||
self.parameters.unparse(writer)?;
|
||||
writer.write(" ")?;
|
||||
self.return_type.unparse(writer)?;
|
||||
writer.write(";")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -722,6 +727,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.borrow().unparse(writer)?;
|
||||
if i != identifiers.len() - 1 {
|
||||
writer.write(", ")?;
|
||||
}
|
||||
}
|
||||
writer.write("}")?;
|
||||
Ok(())
|
||||
}
|
||||
UseStatementLast::Identifier(i) => i.borrow().unparse(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unparse for BlockStatement {
|
||||
fn unparse(&self, writer: &mut IndentWriter) -> std::io::Result<()> {
|
||||
writer.writeln_indented("{")?;
|
||||
|
@ -45,11 +45,9 @@ fn main() {
|
||||
}
|
||||
}
|
||||
Commands::NameAnalysis { paths } => {
|
||||
for path in paths {
|
||||
let result = name_analysis(&path);
|
||||
let result = name_analysis(&paths);
|
||||
if let Err(e) = result {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
eprintln!("{}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,33 +6,41 @@ use deimos::name_analysis::analyze_names;
|
||||
use deimos::name_analysis::symbol_table::SymbolTable;
|
||||
use deimos::parser::{DeimosParser, Rule};
|
||||
use pest::Parser;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn name_analysis(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut compilation_units = vec![];
|
||||
let mut files = SimpleFiles::new();
|
||||
|
||||
for path in paths {
|
||||
let src = std::fs::read_to_string(path).unwrap();
|
||||
let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src);
|
||||
let mut files = SimpleFiles::new();
|
||||
let file_id = files.add(path.display().to_string(), &src);
|
||||
let file_id = files.add(path.display().to_string(), src.clone()); // I don't love this clone
|
||||
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit_pair = pairs.next().unwrap();
|
||||
let mut compilation_unit = build_ast(file_id, compilation_unit_pair);
|
||||
let compilation_unit = build_ast(&path.display().to_string(), file_id, compilation_unit_pair);
|
||||
compilation_units.push(compilation_unit);
|
||||
Ok::<(), Box<dyn std::error::Error>>(())
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}?;
|
||||
}
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let diagnostics = analyze_names(file_id, &mut compilation_unit, &mut symbol_table);
|
||||
|
||||
let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table);
|
||||
if diagnostics.is_empty() {
|
||||
println!("Name analysis complete.");
|
||||
println!("Symbol table\n-------\n{}", symbol_table);
|
||||
Ok(())
|
||||
} else {
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
let config = term::Config::default();
|
||||
for diagnostic in diagnostics {
|
||||
term::emit(&mut writer.lock(), &config, &files, &diagnostic)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub fn pretty_print_parse(path: &PathBuf) {
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit_pair = pairs.next().unwrap();
|
||||
let compilation_unit = build_ast(0, compilation_unit_pair);
|
||||
let compilation_unit = build_ast(&path.display().to_string(), 0, compilation_unit_pair);
|
||||
let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
|
||||
compilation_unit
|
||||
.pretty_print(&mut indent_writer)
|
||||
|
@ -11,7 +11,7 @@ pub fn unparse(path: &PathBuf) {
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit_pair = pairs.next().unwrap();
|
||||
let compilation_unit = build_ast(0, compilation_unit_pair);
|
||||
let compilation_unit = build_ast(&path.display().to_string(), 0, compilation_unit_pair);
|
||||
let mut writer = IndentWriter::new(0, " ", Box::new(std::io::stdout()));
|
||||
compilation_unit
|
||||
.unparse(&mut writer)
|
||||
|
@ -6,5 +6,6 @@ pub mod module;
|
||||
pub mod name_analysis;
|
||||
pub mod object_file;
|
||||
pub mod parser;
|
||||
mod std_core;
|
||||
pub mod util;
|
||||
pub mod vm;
|
||||
|
@ -1,11 +1,13 @@
|
||||
use crate::ast::named::Named;
|
||||
use crate::ast::*;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::fqn_context::FqnContext;
|
||||
use crate::name_analysis::symbol::{FunctionSymbol, ModuleSymbol, SourceDefinition, Symbol, VariableSymbol};
|
||||
use crate::name_analysis::symbol::*;
|
||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
use crate::name_analysis::DiagnosticsContainer;
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use std::cell::RefCell;
|
||||
use std::range::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn handle_insert_error(
|
||||
err: SymbolInsertError,
|
||||
@ -13,14 +15,11 @@ fn handle_insert_error(
|
||||
error_file_id: usize,
|
||||
error_range: Range<usize>,
|
||||
symbol_types: &str,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match err {
|
||||
SymbolInsertError::SymbolAlreadyDefined(s) => {
|
||||
let already_defined_definition = s.definition();
|
||||
|
||||
diagnostics.add(
|
||||
Diagnostic::error()
|
||||
let mut diagnostic = Diagnostic::error()
|
||||
.with_message(format!(
|
||||
"{} symbol '{}' already defined in the current scope.",
|
||||
symbol_types, error_symbol_name,
|
||||
@ -28,33 +27,209 @@ fn handle_insert_error(
|
||||
.with_label(
|
||||
Label::primary(error_file_id, error_range)
|
||||
.with_message("Symbol duplicated here."),
|
||||
)
|
||||
.with_label(
|
||||
Label::secondary(
|
||||
already_defined_definition.file_id(),
|
||||
already_defined_definition.range(),
|
||||
)
|
||||
.with_message("Symbol defined here."),
|
||||
),
|
||||
);
|
||||
|
||||
if let Some(source_definition) = s.definition() {
|
||||
diagnostic = diagnostic.with_label(
|
||||
Label::secondary(source_definition.file_id(), source_definition.range())
|
||||
.with_message("Symbol defined here."),
|
||||
);
|
||||
}
|
||||
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn gather_module_level_declaration(
|
||||
fn gather_fully_qualified_name(
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) {
|
||||
fully_qualified_name.set_scope_id(symbol_table.current_scope_id());
|
||||
}
|
||||
|
||||
fn gather_type_use(
|
||||
type_use: &mut TypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match type_use {
|
||||
TypeUse::Void => {}
|
||||
TypeUse::InterfaceOrClass(interface_or_class_type_use) => {
|
||||
gather_interface_or_class_type_use(
|
||||
interface_or_class_type_use,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
TypeUse::Tuple(tuple_type_use) => {
|
||||
gather_tuple_type_use(tuple_type_use, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
TypeUse::Function(function_type_use) => {
|
||||
gather_function_type_use(function_type_use, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_interface_or_class_type_use(
|
||||
interface_or_class_type_use: &mut InterfaceOrClassTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_fully_qualified_name(&mut interface_or_class_type_use.fqn, symbol_table);
|
||||
gather_generic_arguments(
|
||||
&mut interface_or_class_type_use.generics,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn gather_tuple_type_use(
|
||||
tuple_type_use: &mut TupleTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for generic_argument in &mut tuple_type_use.arguments.0 {
|
||||
gather_type_use(generic_argument, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_function_type_use(
|
||||
function_type_use: &mut FunctionTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn gather_generic_arguments(
|
||||
generic_arguments: &mut GenericArguments,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for argument in &mut generic_arguments.0 {
|
||||
gather_type_use(argument, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn gather_compilation_unit(
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let mut fqn_context = FqnContext::new();
|
||||
if let Some(namespace) = &compilation_unit.namespace {
|
||||
fqn_context.push(namespace.name().to_string());
|
||||
}
|
||||
|
||||
symbol_table.push_scope(&format!("FileScope({})", compilation_unit.file_name));
|
||||
for use_statement in &mut compilation_unit.use_statements {
|
||||
gather_use_statement(use_statement, symbol_table, &mut fqn_context, diagnostics)
|
||||
}
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
gather_module_level_declaration(declaration, symbol_table, &mut fqn_context, diagnostics);
|
||||
}
|
||||
symbol_table.pop_scope();
|
||||
assert_eq!(symbol_table.current_scope_id(), 0);
|
||||
}
|
||||
|
||||
fn handle_use_statement_import(
|
||||
symbol_table: &mut SymbolTable,
|
||||
base_name: &str,
|
||||
identifier: Rc<RefCell<Identifier>>,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let borrowed_identifier = identifier.borrow();
|
||||
let declared_name = borrowed_identifier.name().to_string();
|
||||
let insert_result = symbol_table.insert_use_statement_symbol(UseStatementSymbol::new(
|
||||
&format!("{}::{}", base_name, &declared_name),
|
||||
&declared_name,
|
||||
Some(identifier.clone()),
|
||||
));
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
err,
|
||||
&declared_name,
|
||||
borrowed_identifier.file_id,
|
||||
borrowed_identifier.range,
|
||||
"Use statement",
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
drop(borrowed_identifier);
|
||||
let mut mutable_borrowed_identifier = identifier.borrow_mut();
|
||||
mutable_borrowed_identifier.set_scope_id(symbol_table.current_scope_id());
|
||||
|
||||
let use_statement_symbol = symbol_table
|
||||
.lookup(
|
||||
&declared_name,
|
||||
mutable_borrowed_identifier.scope_id().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mutable_borrowed_identifier.set_symbol(use_statement_symbol);
|
||||
}
|
||||
|
||||
fn gather_use_statement(
|
||||
use_statement: &mut UseStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
if use_statement.is_star() {
|
||||
todo!()
|
||||
}
|
||||
let base_name = use_statement.base_name().to_string();
|
||||
match &mut use_statement.last {
|
||||
UseStatementLast::Identifier(identifier) => {
|
||||
handle_use_statement_import(symbol_table, &base_name, identifier.clone(), diagnostics)
|
||||
}
|
||||
UseStatementLast::Identifiers(identifiers) => {
|
||||
for identifier in identifiers {
|
||||
handle_use_statement_import(
|
||||
symbol_table,
|
||||
&base_name,
|
||||
identifier.clone(),
|
||||
diagnostics,
|
||||
)
|
||||
}
|
||||
}
|
||||
UseStatementLast::Star => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_module_level_declaration(
|
||||
declaration: &mut ModuleLevelDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use ModuleLevelDeclaration::*;
|
||||
match declaration {
|
||||
Module(module_declaration) => {
|
||||
gather_module_declaration(module_declaration, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
Class(class_declaration) => {
|
||||
gather_class_declaration(class_declaration, symbol_table, fqn_context, diagnostics)
|
||||
}
|
||||
Function(function_definition) => {
|
||||
gather_function_definition(function_definition, symbol_table, fqn_context, diagnostics)
|
||||
}
|
||||
PlatformFunction(platform_function_definition) => {
|
||||
gather_platform_function_definition(
|
||||
platform_function_definition,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -63,7 +238,7 @@ fn gather_module_declaration(
|
||||
declaration: &mut ModuleDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
// 1. Add mod identifier symbol
|
||||
// 2. Update fqn context
|
||||
@ -73,15 +248,12 @@ fn gather_module_declaration(
|
||||
|
||||
let module_name = declaration.identifier.name();
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
&module_name,
|
||||
Symbol::Module(ModuleSymbol::new(
|
||||
let insert_result = symbol_table.insert_module_symbol(ModuleSymbol::new(
|
||||
&fqn_context.resolve(&module_name),
|
||||
&module_name,
|
||||
declaration.is_public,
|
||||
&declaration.identifier,
|
||||
)),
|
||||
);
|
||||
Some(&declaration.identifier),
|
||||
));
|
||||
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
@ -96,31 +268,58 @@ fn gather_module_declaration(
|
||||
|
||||
fqn_context.push(module_name.to_string());
|
||||
|
||||
symbol_table.push_scope(&format!("Module '{}' Scope", module_name));
|
||||
symbol_table.push_scope(&format!("ModuleScope({})", module_name));
|
||||
for inner_declaration in &mut declaration.declarations {
|
||||
gather_module_level_declaration(inner_declaration, symbol_table, fqn_context, diagnostics);
|
||||
}
|
||||
symbol_table.pop_scope()
|
||||
}
|
||||
|
||||
fn gather_class_declaration(
|
||||
class_declaration: &mut ClassDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let declared_name = class_declaration.identifier.name();
|
||||
let resolved_name = fqn_context.resolve(&declared_name);
|
||||
|
||||
let insert_result = symbol_table.insert_type_symbol(TypeSymbol::new(
|
||||
&resolved_name,
|
||||
&declared_name,
|
||||
class_declaration.is_public,
|
||||
Some(&class_declaration.identifier),
|
||||
));
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
err,
|
||||
&declared_name,
|
||||
class_declaration.identifier.file_id,
|
||||
class_declaration.identifier.range,
|
||||
"interface/class",
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
// todo: scopes, generics, etc.
|
||||
}
|
||||
|
||||
fn gather_function_definition(
|
||||
function: &mut FunctionDefinition,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let declared_name = function.identifier.name();
|
||||
let resolved_name = fqn_context.resolve(&declared_name);
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
&declared_name,
|
||||
Symbol::Function(FunctionSymbol::new(
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
&resolved_name,
|
||||
&declared_name,
|
||||
function.is_public,
|
||||
&function.identifier,
|
||||
)),
|
||||
);
|
||||
false,
|
||||
Some(&function.identifier),
|
||||
));
|
||||
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
@ -148,11 +347,55 @@ fn gather_function_definition(
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
fn gather_platform_function_definition(
|
||||
platform_function_declaration: &mut PlatformFunctionDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let declared_name = platform_function_declaration.identifier.name();
|
||||
let fully_qualified_name = fqn_context.resolve(&declared_name);
|
||||
|
||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
&fully_qualified_name,
|
||||
&declared_name,
|
||||
platform_function_declaration.is_public,
|
||||
true,
|
||||
Some(&platform_function_declaration.identifier),
|
||||
));
|
||||
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
err,
|
||||
&declared_name,
|
||||
platform_function_declaration.identifier.file_id,
|
||||
platform_function_declaration.identifier.range,
|
||||
"(Platform-) Function",
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
let declared_name_as_string = platform_function_declaration.identifier.name().to_string();
|
||||
|
||||
platform_function_declaration
|
||||
.identifier
|
||||
.set_scope_id(symbol_table.current_scope_id());
|
||||
|
||||
symbol_table.push_scope(&format!("FunctionScope({})", declared_name_as_string));
|
||||
gather_parameters(
|
||||
&mut platform_function_declaration.parameters,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
diagnostics,
|
||||
);
|
||||
symbol_table.pop_scope();
|
||||
}
|
||||
|
||||
fn gather_parameters(
|
||||
parameters: &mut Parameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for parameter in &mut parameters.0 {
|
||||
gather_parameter(parameter, symbol_table, fqn_context, diagnostics);
|
||||
@ -163,18 +406,14 @@ fn gather_parameter(
|
||||
parameter: &mut Parameter,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let parameter_name = parameter.identifier.name();
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
|
||||
¶meter_name,
|
||||
Symbol::Variable(VariableSymbol::new(
|
||||
¶meter_name,
|
||||
false,
|
||||
SourceDefinition::from_identifier(¶meter.identifier),
|
||||
)),
|
||||
);
|
||||
Some(¶meter.identifier),
|
||||
));
|
||||
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
@ -190,13 +429,20 @@ fn gather_parameter(
|
||||
parameter
|
||||
.identifier
|
||||
.set_scope_id(symbol_table.current_scope_id());
|
||||
|
||||
gather_type_use(
|
||||
&mut parameter.type_use,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
diagnostics,
|
||||
)
|
||||
}
|
||||
|
||||
fn gather_function_body(
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::FunctionBody::*;
|
||||
match function_body {
|
||||
@ -209,7 +455,7 @@ fn gather_block_statement(
|
||||
block: &mut BlockStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
symbol_table.push_scope("BlockStatementScope");
|
||||
gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics);
|
||||
@ -220,7 +466,7 @@ fn gather_block_statement_inner(
|
||||
block: &mut BlockStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for statement in &mut block.statements {
|
||||
gather_statement(statement, symbol_table, fqn_context, diagnostics);
|
||||
@ -234,7 +480,7 @@ fn gather_statement(
|
||||
statement: &mut Statement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::Statement::*;
|
||||
match statement {
|
||||
@ -247,6 +493,9 @@ fn gather_statement(
|
||||
AssignStatement(assign_statement) => {
|
||||
gather_assign_statement(assign_statement, symbol_table, fqn_context, diagnostics)
|
||||
}
|
||||
CallStatement(call_statement) => {
|
||||
gather_call_statement(call_statement, symbol_table, diagnostics)
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -254,18 +503,15 @@ fn gather_statement(
|
||||
fn gather_variable_declaration(
|
||||
variable_declaration: &mut VariableDeclarationStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let variable_name = variable_declaration.identifier.name();
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
&variable_name,
|
||||
Symbol::Variable(VariableSymbol::new(
|
||||
let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
|
||||
&variable_name,
|
||||
variable_declaration.is_mutable,
|
||||
SourceDefinition::from_identifier(&variable_declaration.identifier),
|
||||
)),
|
||||
);
|
||||
Some(&variable_declaration.identifier),
|
||||
));
|
||||
|
||||
if let Err(err) = insert_result {
|
||||
handle_insert_error(
|
||||
@ -291,29 +537,156 @@ fn gather_assign_statement(
|
||||
assign_statement: &mut AssignStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut assign_statement.lhs, symbol_table, diagnostics);
|
||||
gather_expression(&mut assign_statement.rhs, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn gather_call_statement(
|
||||
call_statement: &mut CallStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut call_statement.0, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn gather_expression(
|
||||
expression: &mut Expression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::Expression::*;
|
||||
match expression {
|
||||
Ternary(ternary_expression) => {
|
||||
gather_ternary_expression(ternary_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Binary(binary_expression) => {
|
||||
gather_binary_expression(binary_expression, symbol_table, diagnostics);
|
||||
}
|
||||
UnaryPrefix(prefix_expression) => {
|
||||
gather_prefix_expression(prefix_expression, symbol_table, diagnostics);
|
||||
}
|
||||
UnarySuffix(suffix_expression) => {
|
||||
gather_suffix_expression(suffix_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Call(call_expression) => {
|
||||
gather_call_expression(call_expression, symbol_table, diagnostics);
|
||||
}
|
||||
ObjectAccess(object_access) => {
|
||||
gather_object_access(object_access, symbol_table, diagnostics);
|
||||
}
|
||||
Literal(literal) => {
|
||||
gather_literal(literal, symbol_table, diagnostics);
|
||||
}
|
||||
FullyQualifiedName(fully_qualified_name) => {
|
||||
gather_fully_qualified_name(fully_qualified_name, symbol_table);
|
||||
}
|
||||
_ => {}
|
||||
Closure(closure) => {
|
||||
gather_closure(closure, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_fully_qualified_name(
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
fn gather_ternary_expression(
|
||||
ternary_expression: &mut TernaryExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
fully_qualified_name.set_scope_id(symbol_table.current_scope_id());
|
||||
gather_expression(&mut ternary_expression.condition, symbol_table, diagnostics);
|
||||
gather_expression(
|
||||
&mut ternary_expression.true_expression,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
gather_expression(
|
||||
&mut ternary_expression.false_expression,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn gather_binary_expression(
|
||||
binary_expression: &mut BinaryExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut binary_expression.left, symbol_table, diagnostics);
|
||||
gather_expression(&mut binary_expression.right, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn gather_prefix_expression(
|
||||
prefix_expression: &mut PrefixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut prefix_expression.expression, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn gather_suffix_expression(
|
||||
suffix_expression: &mut SuffixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut suffix_expression.expression, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn gather_call_expression(
|
||||
call_expression: &mut CallExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut call_expression.callee, symbol_table, diagnostics);
|
||||
if let Some(turbo_fish) = &mut call_expression.turbo_fish {
|
||||
gather_turbo_fish(turbo_fish, symbol_table, diagnostics);
|
||||
}
|
||||
for call_argument in &mut call_expression.arguments.0 {
|
||||
gather_expression(&mut call_argument.0, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_turbo_fish(
|
||||
turbo_fish: &mut TurboFish,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn gather_closure(
|
||||
closure: &mut Closure,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn gather_object_access(
|
||||
object_access: &mut ObjectAccess,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
gather_expression(&mut object_access.receiver, symbol_table, diagnostics);
|
||||
for object_navigation in &mut object_access.navigations.0 {
|
||||
match object_navigation {
|
||||
ObjectNavigation::Index(index_expression) => {
|
||||
gather_expression(index_expression, symbol_table, diagnostics);
|
||||
}
|
||||
ObjectNavigation::Identifier(identifier) => {
|
||||
identifier.set_scope_id(symbol_table.current_scope_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_literal(
|
||||
literal: &mut Literal,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match literal {
|
||||
Literal::DString(d_string) => todo!(),
|
||||
Literal::BacktickString(backtick_string) => todo!(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
use crate::ast::named::Named;
|
||||
use crate::ast::{CompilationUnit, Identifier};
|
||||
use crate::ast::CompilationUnit;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::fqn_context::FqnContext;
|
||||
use crate::name_analysis::gather::gather_module_level_declaration;
|
||||
use crate::name_analysis::resolve::resolve_module_level_declaration;
|
||||
use crate::name_analysis::gather::gather_compilation_unit;
|
||||
use crate::name_analysis::resolve::resolve_compilation_unit;
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use log::debug;
|
||||
|
||||
mod fqn_context;
|
||||
mod gather;
|
||||
@ -14,63 +11,20 @@ mod resolve;
|
||||
pub mod symbol;
|
||||
pub mod symbol_table;
|
||||
|
||||
pub(self) struct DiagnosticsContainer {
|
||||
file_id: usize,
|
||||
diagnostics: Vec<DmDiagnostic>,
|
||||
}
|
||||
|
||||
impl DiagnosticsContainer {
|
||||
pub fn new(file_id: usize) -> DiagnosticsContainer {
|
||||
DiagnosticsContainer {
|
||||
file_id,
|
||||
diagnostics: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, diagnostic: DmDiagnostic) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
pub fn add_error_at_identifier(&mut self, msg: &str, identifier: &Identifier) {
|
||||
self.diagnostics.push(
|
||||
Diagnostic::error()
|
||||
.with_message(msg)
|
||||
.with_label(Label::primary(self.file_id, identifier.range)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<DmDiagnostic>> for DiagnosticsContainer {
|
||||
fn into(self) -> Vec<DmDiagnostic> {
|
||||
self.diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze_names(
|
||||
file_id: usize,
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
compilation_units: &mut Vec<CompilationUnit>,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Vec<DmDiagnostic> {
|
||||
let mut diagnostics = DiagnosticsContainer::new(file_id);
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let mut fqn_context = FqnContext::new();
|
||||
if let Some(namespace) = &compilation_unit.namespace {
|
||||
fqn_context.push(namespace.name().to_string());
|
||||
// gather symbols
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||
}
|
||||
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
gather_module_level_declaration(
|
||||
declaration,
|
||||
symbol_table,
|
||||
&mut fqn_context,
|
||||
&mut diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(symbol_table.current_scope_id(), 0);
|
||||
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
resolve_module_level_declaration(declaration, symbol_table, &mut diagnostics);
|
||||
// resolve symbols
|
||||
for compilation_unit in compilation_units.iter_mut() {
|
||||
resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
||||
}
|
||||
|
||||
diagnostics.into()
|
||||
@ -81,26 +35,36 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::ast::build::build_ast;
|
||||
use crate::parser::{DeimosParser, Rule};
|
||||
use crate::std_core::add_std_core_symbols;
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use indoc::indoc;
|
||||
use pest::Parser;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn assert_no_diagnostics(src: &str) {
|
||||
fn assert_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable {
|
||||
let mut files = SimpleFiles::new();
|
||||
let test_file_id = files.add("test.dm", src);
|
||||
let mut compilation_units = vec![];
|
||||
|
||||
let parse_result = DeimosParser::parse(Rule::CompilationUnit, src);
|
||||
for (file_name, source) in sources {
|
||||
let file_id = files.add(file_name, source);
|
||||
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
|
||||
if let Err(err) = &parse_result {
|
||||
panic!("{:?}", err);
|
||||
panic!("{}", err);
|
||||
}
|
||||
let mut pairs = parse_result.unwrap();
|
||||
if pairs.as_str().trim() != source.trim() {
|
||||
panic!("Parsing did not consume entire input.");
|
||||
}
|
||||
|
||||
let compilation_unit_pair = parse_result.unwrap().next().unwrap();
|
||||
let mut ast = build_ast(test_file_id, compilation_unit_pair);
|
||||
compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap()))
|
||||
}
|
||||
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
add_std_core_symbols(&mut symbol_table).expect("Failed to add std_core_symbols");
|
||||
|
||||
let diagnostics = analyze_names(test_file_id, &mut ast, &mut symbol_table);
|
||||
let diagnostics = analyze_names(&mut compilation_units, &mut symbol_table);
|
||||
|
||||
if !diagnostics.is_empty() {
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
@ -113,16 +77,50 @@ mod tests {
|
||||
eprintln!("{}", symbol_table);
|
||||
panic!("Diagnostics was not empty!");
|
||||
}
|
||||
|
||||
for compilation_unit in &compilation_units {
|
||||
dbg!(compilation_unit);
|
||||
}
|
||||
|
||||
symbol_table
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn params_seen() {
|
||||
assert_no_diagnostics(
|
||||
r#"
|
||||
let sources: HashMap<&str, &str> = HashMap::from([(
|
||||
"main.dm",
|
||||
indoc! {"
|
||||
fn main(args: Array<String>) {
|
||||
let x = args;
|
||||
}"},
|
||||
)]);
|
||||
|
||||
assert_no_diagnostics(sources);
|
||||
}
|
||||
"#,
|
||||
)
|
||||
|
||||
#[test]
|
||||
fn two_files() {
|
||||
let sources: HashMap<&str, &str> = HashMap::from([
|
||||
(
|
||||
"main.dm",
|
||||
indoc! {"
|
||||
use test::Greeter;
|
||||
|
||||
fn main(args: Array<String>) {
|
||||
println(\"Hello, World!\");
|
||||
}
|
||||
"},
|
||||
),
|
||||
(
|
||||
"deps.dm",
|
||||
indoc! {"
|
||||
ns test;
|
||||
|
||||
pub class Greeter {}
|
||||
"},
|
||||
),
|
||||
]);
|
||||
|
||||
assert_no_diagnostics(sources);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,229 @@
|
||||
use crate::ast::named::Named;
|
||||
use crate::ast::*;
|
||||
use crate::diagnostic::DmDiagnostic;
|
||||
use crate::name_analysis::symbol_table::SymbolTable;
|
||||
use crate::name_analysis::DiagnosticsContainer;
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
|
||||
fn resolve_fully_qualified_name(
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let lookup_result = symbol_table.lookup(
|
||||
fully_qualified_name.name().as_ref(),
|
||||
fully_qualified_name.scope_id().expect(&format!(
|
||||
"FullyQualifiedName has no scope_id set: {:?}",
|
||||
fully_qualified_name
|
||||
)),
|
||||
);
|
||||
match lookup_result {
|
||||
Ok(symbol) => {
|
||||
fully_qualified_name.set_symbol(symbol.clone());
|
||||
}
|
||||
Err(e) => diagnostics.push(
|
||||
Diagnostic::error()
|
||||
.with_message(format!(
|
||||
"No symbol with name '{}' found in current scope.",
|
||||
fully_qualified_name.name()
|
||||
))
|
||||
.with_label(Label::primary(
|
||||
fully_qualified_name.file_id,
|
||||
fully_qualified_name.range,
|
||||
)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_type_use(
|
||||
type_use: &mut TypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match type_use {
|
||||
TypeUse::Void => {}
|
||||
TypeUse::InterfaceOrClass(interface_or_class_type_use) => {
|
||||
resolve_interface_or_class_type_use(
|
||||
interface_or_class_type_use,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
TypeUse::Tuple(tuple_type_use) => {
|
||||
resolve_tuple_type_use(tuple_type_use, symbol_table, diagnostics);
|
||||
}
|
||||
TypeUse::Function(function_type_use) => {
|
||||
resolve_function_type_use(function_type_use, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_interface_or_class_type_use(
|
||||
interface_or_class_type_use: &mut InterfaceOrClassTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_fully_qualified_name(
|
||||
&mut interface_or_class_type_use.fqn,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
resolve_generic_arguments(
|
||||
&mut interface_or_class_type_use.generics,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn resolve_tuple_type_use(
|
||||
tuple_type_use: &mut TupleTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_tuple_arguments(&mut tuple_type_use.arguments, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_function_type_use(
|
||||
function_type_use: &mut FunctionTypeUse,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_parameters(&mut function_type_use.parameters, symbol_table, diagnostics);
|
||||
resolve_return_type(
|
||||
&mut function_type_use.return_type,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn resolve_generic_arguments(
|
||||
generic_arguments: &mut GenericArguments,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for generic_argument in &mut generic_arguments.0 {
|
||||
resolve_type_use(generic_argument, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_tuple_arguments(
|
||||
tuple_type_use: &mut TupleArguments,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for type_use in &mut tuple_type_use.0 {
|
||||
resolve_type_use(type_use, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_implements_list(
|
||||
implements_list: &mut ImplementsList,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn resolve_parameters(
|
||||
parameters: &mut Parameters,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for parameter in &mut parameters.0 {
|
||||
resolve_type_use(&mut parameter.type_use, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_return_type(
|
||||
return_type: &mut ReturnType,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_type_use(&mut return_type.declared_type, symbol_table, diagnostics);
|
||||
resolve_references(&mut return_type.references, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_references(
|
||||
references: &mut References,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for reference in &mut references.0 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_use_statement(
|
||||
use_statement: &mut UseStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
if use_statement.is_star() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
let base_name = use_statement.base_name().to_string();
|
||||
|
||||
match &use_statement.last {
|
||||
UseStatementLast::Identifier(identifier) => {
|
||||
let borrowed_identifier = identifier.borrow();
|
||||
let declared_name = borrowed_identifier.name().to_string();
|
||||
let fqn = format!("{}::{}", &base_name, &declared_name);
|
||||
let lookup_result =
|
||||
symbol_table.lookup_usable_by_fqn(&fqn, borrowed_identifier.scope_id().unwrap());
|
||||
drop(borrowed_identifier);
|
||||
|
||||
if let Err(_) = lookup_result {
|
||||
diagnostics.push(
|
||||
Diagnostic::error()
|
||||
.with_message(&format!("Unable to find symbol '{}'.", fqn))
|
||||
.with_label(Label::primary(use_statement.file_id, use_statement.range)),
|
||||
);
|
||||
} else {
|
||||
let mut mutable_borrowed_identifier = identifier.borrow_mut();
|
||||
let use_statement_symbol = mutable_borrowed_identifier
|
||||
.symbol_mut()
|
||||
.unwrap()
|
||||
.unwrap_use_statement_symbol();
|
||||
let mut mutable_borrowed_use_statement_symbol = use_statement_symbol.borrow_mut();
|
||||
mutable_borrowed_use_statement_symbol.set_referenced_symbol(lookup_result.unwrap())
|
||||
}
|
||||
}
|
||||
UseStatementLast::Identifiers(identifiers) => {}
|
||||
UseStatementLast::Star => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_compilation_unit(
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for use_statement in &mut compilation_unit.use_statements {
|
||||
resolve_use_statement(use_statement, symbol_table, diagnostics);
|
||||
}
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
resolve_module_level_declaration(declaration, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn resolve_module_level_declaration(
|
||||
declaration: &mut ModuleLevelDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::ModuleLevelDeclaration::*;
|
||||
match declaration {
|
||||
Function(function_definition) => {
|
||||
resolve_function_definition(function_definition, symbol_table, diagnostics)
|
||||
}
|
||||
PlatformFunction(platform_function_declaration) => resolve_platform_function_declaration(
|
||||
platform_function_declaration,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
),
|
||||
Class(class_declaration) => {
|
||||
// todo
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -21,15 +231,42 @@ pub(super) fn resolve_module_level_declaration(
|
||||
fn resolve_function_definition(
|
||||
function_definition: &mut FunctionDefinition,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_parameters(
|
||||
&mut function_definition.parameters,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
resolve_return_type(
|
||||
&mut function_definition.return_type,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
resolve_function_body(&mut function_definition.body, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_platform_function_declaration(
|
||||
platform_function_declaration: &mut PlatformFunctionDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_parameters(
|
||||
&mut platform_function_declaration.parameters,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
resolve_return_type(
|
||||
&mut platform_function_declaration.return_type,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn resolve_function_body(
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::FunctionBody::*;
|
||||
match function_body {
|
||||
@ -41,7 +278,7 @@ fn resolve_function_body(
|
||||
fn resolve_block(
|
||||
block_statement: &mut BlockStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for statement in block_statement.statements.iter_mut() {
|
||||
resolve_statement(statement, symbol_table, diagnostics);
|
||||
@ -54,7 +291,7 @@ fn resolve_block(
|
||||
fn resolve_statement(
|
||||
statement: &mut Statement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::Statement::*;
|
||||
match statement {
|
||||
@ -75,7 +312,7 @@ fn resolve_statement(
|
||||
fn resolve_variable_declaration(
|
||||
variable_declaration: &mut VariableDeclarationStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
if let Some(initializer) = &mut variable_declaration.initializer {
|
||||
resolve_expression(initializer, symbol_table, diagnostics)
|
||||
@ -85,7 +322,7 @@ fn resolve_variable_declaration(
|
||||
fn resolve_assign_statement(
|
||||
assign_statement: &mut AssignStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut assign_statement.lhs, symbol_table, diagnostics);
|
||||
resolve_expression(&mut assign_statement.rhs, symbol_table, diagnostics);
|
||||
@ -94,7 +331,7 @@ fn resolve_assign_statement(
|
||||
fn resolve_call_statement(
|
||||
call_statement: &mut CallStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut call_statement.0, symbol_table, diagnostics)
|
||||
}
|
||||
@ -102,42 +339,151 @@ fn resolve_call_statement(
|
||||
fn resolve_expression(
|
||||
expression: &mut Expression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
use crate::ast::Expression::*;
|
||||
match expression {
|
||||
Ternary(ternary_expression) => {
|
||||
resolve_ternary_expression(ternary_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Binary(binary_expression) => {
|
||||
resolve_binary_expression(binary_expression, symbol_table, diagnostics);
|
||||
}
|
||||
UnaryPrefix(prefix_expression) => {
|
||||
resolve_prefix_expression(prefix_expression, symbol_table, diagnostics);
|
||||
}
|
||||
UnarySuffix(suffix_expression) => {
|
||||
resolve_suffix_expression(suffix_expression, symbol_table, diagnostics);
|
||||
}
|
||||
Call(call_expression) => {
|
||||
resolve_call_expression(call_expression, symbol_table, diagnostics)
|
||||
}
|
||||
ObjectAccess(object_access) => {
|
||||
resolve_object_access(object_access, symbol_table, diagnostics);
|
||||
}
|
||||
FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table, diagnostics),
|
||||
Literal(_) => {}
|
||||
_ => todo!(),
|
||||
Literal(literal) => {
|
||||
resolve_literal(literal, symbol_table, diagnostics);
|
||||
}
|
||||
Closure(closure) => {
|
||||
resolve_closure(closure, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_fully_qualified_name(
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
fn resolve_ternary_expression(
|
||||
ternary_expression: &mut TernaryExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut DiagnosticsContainer,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
let lookup_result = symbol_table.lookup(
|
||||
fully_qualified_name.name().as_ref(),
|
||||
fully_qualified_name.scope_id().expect(&format!(
|
||||
"FullyQualifiedName has no scope_id set: {:?}",
|
||||
fully_qualified_name
|
||||
)),
|
||||
resolve_expression(&mut ternary_expression.condition, symbol_table, diagnostics);
|
||||
resolve_expression(
|
||||
&mut ternary_expression.true_expression,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
match lookup_result {
|
||||
Ok(symbol) => {
|
||||
fully_qualified_name.set_symbol(symbol.clone());
|
||||
resolve_expression(
|
||||
&mut ternary_expression.false_expression,
|
||||
symbol_table,
|
||||
diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
fn resolve_binary_expression(
|
||||
binary_expression: &mut BinaryExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut binary_expression.left, symbol_table, diagnostics);
|
||||
resolve_expression(&mut binary_expression.right, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_prefix_expression(
|
||||
prefix_expression: &mut PrefixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut prefix_expression.expression, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_suffix_expression(
|
||||
suffix_expression: &mut SuffixExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut suffix_expression.expression, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_call_expression(
|
||||
call_expression: &mut CallExpression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut call_expression.callee, symbol_table, diagnostics);
|
||||
if let Some(turbo_fish) = &mut call_expression.turbo_fish {
|
||||
resolve_turbo_fish(turbo_fish, symbol_table, diagnostics);
|
||||
}
|
||||
Err(e) => diagnostics.add(
|
||||
Diagnostic::error()
|
||||
.with_message(format!(
|
||||
"No symbol with name '{}' found in current scope.",
|
||||
fully_qualified_name.name()
|
||||
))
|
||||
.with_label(Label::primary(
|
||||
fully_qualified_name.file_id,
|
||||
fully_qualified_name.range,
|
||||
)),
|
||||
),
|
||||
resolve_call_arguments(&mut call_expression.arguments, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_turbo_fish(
|
||||
turbo_fish: &mut TurboFish,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn resolve_call_arguments(
|
||||
call_arguments: &mut CallArguments,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
for argument in &mut call_arguments.0 {
|
||||
resolve_call_argument(argument, symbol_table, diagnostics);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_call_argument(
|
||||
call_argument: &mut CallArgument,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
resolve_expression(&mut call_argument.0, symbol_table, diagnostics);
|
||||
}
|
||||
|
||||
fn resolve_closure(
|
||||
closure: &mut Closure,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn resolve_object_access(
|
||||
object_access: &mut ObjectAccess,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn resolve_literal(
|
||||
literal: &mut Literal,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
match literal {
|
||||
Literal::DString(d_string) => resolve_d_string(d_string, symbol_table, diagnostics),
|
||||
Literal::BacktickString(d_string) => resolve_d_string(d_string, symbol_table, diagnostics),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_d_string(
|
||||
d_string: &mut DString,
|
||||
symbol_table: &mut SymbolTable,
|
||||
diagnostics: &mut Vec<DmDiagnostic>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::ast::Identifier;
|
||||
use std::cell::RefCell;
|
||||
use crate::ast::{Identifier, UseStatement};
|
||||
use std::fmt::Display;
|
||||
use std::range::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SourceDefinition {
|
||||
@ -16,6 +18,22 @@ impl SourceDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_identifier_rc(identifier: Rc<RefCell<Identifier>>) -> Self {
|
||||
let borrowed = identifier.borrow();
|
||||
SourceDefinition {
|
||||
file_id: borrowed.file_id,
|
||||
range: borrowed.range,
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(note = "Use identifier instead.")]
|
||||
pub fn from_use_statement(use_statement: &UseStatement) -> Self {
|
||||
SourceDefinition {
|
||||
file_id: use_statement.file_id,
|
||||
range: use_statement.range,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_id(&self) -> usize {
|
||||
self.file_id
|
||||
}
|
||||
@ -25,27 +43,39 @@ impl SourceDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SymbolInner {
|
||||
fn declared_name(&self) -> &str;
|
||||
fn definition(&self) -> Option<SourceDefinition>;
|
||||
}
|
||||
|
||||
/* Symbol */
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Symbol {
|
||||
Function(FunctionSymbol),
|
||||
Variable(VariableSymbol),
|
||||
Module(ModuleSymbol),
|
||||
UseStatement(Rc<RefCell<UseStatementSymbol>>),
|
||||
Module(Rc<ModuleSymbol>),
|
||||
Type(Rc<TypeSymbol>),
|
||||
Function(Rc<FunctionSymbol>),
|
||||
Parameter(Rc<ParameterSymbol>),
|
||||
Variable(Rc<VariableSymbol>),
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> &str {
|
||||
pub fn definition(&self) -> Option<SourceDefinition> {
|
||||
match self {
|
||||
Symbol::Function(s) => s.declared_name.as_str(),
|
||||
Symbol::Variable(s) => s.name.as_str(),
|
||||
Symbol::Module(s) => s.declared_name.as_str(),
|
||||
Symbol::UseStatement(s) => s.borrow().definition.clone(),
|
||||
Symbol::Module(s) => s.definition(),
|
||||
Symbol::Type(s) => s.definition(),
|
||||
Symbol::Function(s) => s.definition(),
|
||||
Symbol::Parameter(s) => s.definition(),
|
||||
Symbol::Variable(s) => s.definition(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definition(&self) -> &SourceDefinition {
|
||||
pub fn unwrap_use_statement_symbol(&self) -> Rc<RefCell<UseStatementSymbol>> {
|
||||
match self {
|
||||
Symbol::Function(s) => s.definition(),
|
||||
Symbol::Module(s) => s.definition(),
|
||||
Symbol::Variable(s) => s.definition(),
|
||||
Symbol::UseStatement(s) => s.clone(),
|
||||
_ => panic!("unwrap_use_statement_symbol called on non-use statement symbol"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,19 +84,170 @@ impl Display for Symbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use Symbol::*;
|
||||
match self {
|
||||
Function(function_symbol) => write!(f, "{}", function_symbol),
|
||||
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
|
||||
UseStatement(use_statement_symbol) => write!(f, "{}", use_statement_symbol.borrow()),
|
||||
Module(module_symbol) => write!(f, "{}", module_symbol),
|
||||
Type(class_symbol) => write!(f, "{}", class_symbol),
|
||||
Function(function_symbol) => write!(f, "{}", function_symbol),
|
||||
Parameter(parameter_symbol) => write!(f, "{}", parameter_symbol),
|
||||
Variable(variable_symbol) => write!(f, "{}", variable_symbol),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use-statement */
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionSymbol {
|
||||
pub struct UseStatementSymbol {
|
||||
pub fqn: String,
|
||||
pub declared_name: String,
|
||||
pub is_public: bool,
|
||||
definition: SourceDefinition,
|
||||
definition: Option<SourceDefinition>,
|
||||
referenced_symbol: Option<Box<Symbol>>
|
||||
}
|
||||
|
||||
impl UseStatementSymbol {
|
||||
pub fn new(fqn: &str, declared_name: &str, identifier: Option<Rc<RefCell<Identifier>>>) -> Self {
|
||||
UseStatementSymbol {
|
||||
fqn: fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
definition: identifier.map(SourceDefinition::from_identifier_rc),
|
||||
referenced_symbol: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_referenced_symbol(&mut self, referenced_symbol: Symbol) {
|
||||
self.referenced_symbol = Some(Box::new(referenced_symbol));
|
||||
}
|
||||
|
||||
pub fn referenced_symbol(&self) -> Option<Box<Symbol>> {
|
||||
self.referenced_symbol.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for UseStatementSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for UseStatementSymbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"UseStatementSymbol(fqn = {}, declared_name = {})",
|
||||
self.fqn, self.declared_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Module */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleSymbol {
|
||||
fqn: String,
|
||||
declared_name: String,
|
||||
is_public: bool,
|
||||
definition: Option<SourceDefinition>,
|
||||
}
|
||||
|
||||
impl ModuleSymbol {
|
||||
pub fn new(
|
||||
fqn: &str,
|
||||
declared_name: &str,
|
||||
is_public: bool,
|
||||
identifier: Option<&Identifier>,
|
||||
) -> ModuleSymbol {
|
||||
ModuleSymbol {
|
||||
fqn: fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
is_public,
|
||||
definition: identifier.map(SourceDefinition::from_identifier),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for ModuleSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
self.declared_name.as_str()
|
||||
}
|
||||
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ModuleSymbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ModuleSymbol(name = {}, is_public = {})",
|
||||
self.fqn, self.is_public
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Class */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeSymbol {
|
||||
fqn: String,
|
||||
declared_name: String,
|
||||
is_public: bool,
|
||||
definition: Option<SourceDefinition>,
|
||||
}
|
||||
|
||||
impl TypeSymbol {
|
||||
pub fn new(fqn: &str, declared_name: &str, is_public: bool, identifier: Option<&Identifier>) -> Self {
|
||||
TypeSymbol {
|
||||
fqn: fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
is_public,
|
||||
definition: identifier.map(SourceDefinition::from_identifier),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fqn(&self) -> &str {
|
||||
&self.fqn
|
||||
}
|
||||
|
||||
pub fn is_public(&self) -> bool {
|
||||
self.is_public
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for TypeSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TypeSymbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TypeSymbol(fqn = {}, declared_name = {})",
|
||||
self.fqn, self.declared_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Function */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionSymbol {
|
||||
fqn: String,
|
||||
declared_name: String,
|
||||
is_public: bool,
|
||||
is_platform: bool,
|
||||
definition: Option<SourceDefinition>,
|
||||
}
|
||||
|
||||
impl FunctionSymbol {
|
||||
@ -74,18 +255,30 @@ impl FunctionSymbol {
|
||||
fqn: &str,
|
||||
declared_name: &str,
|
||||
is_public: bool,
|
||||
identifier: &Identifier,
|
||||
is_platform: bool,
|
||||
identifier: Option<&Identifier>,
|
||||
) -> FunctionSymbol {
|
||||
FunctionSymbol {
|
||||
fqn: fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
is_public,
|
||||
definition: SourceDefinition::from_identifier(identifier),
|
||||
is_platform,
|
||||
definition: identifier.map(SourceDefinition::from_identifier),
|
||||
}
|
||||
}
|
||||
|
||||
fn definition(&self) -> &SourceDefinition {
|
||||
&self.definition
|
||||
pub fn fqn(&self) -> &str {
|
||||
&self.fqn
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for FunctionSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
self.declared_name.as_str()
|
||||
}
|
||||
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,24 +292,69 @@ impl Display for FunctionSymbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/* Parameter */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParameterSymbol {
|
||||
declared_name: String,
|
||||
definition: Option<SourceDefinition>,
|
||||
}
|
||||
|
||||
impl ParameterSymbol {
|
||||
pub fn new(declared_name: &str, identifier: Option<&Identifier>) -> Self {
|
||||
ParameterSymbol {
|
||||
declared_name: declared_name.to_string(),
|
||||
definition: identifier.map(SourceDefinition::from_identifier),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for ParameterSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
&self.declared_name
|
||||
}
|
||||
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ParameterSymbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ParameterSymbol({})",
|
||||
self.declared_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Variable */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VariableSymbol {
|
||||
pub name: String,
|
||||
pub is_mutable: bool,
|
||||
definition: SourceDefinition,
|
||||
declared_name: String,
|
||||
is_mutable: bool,
|
||||
definition: Option<SourceDefinition>,
|
||||
}
|
||||
|
||||
impl VariableSymbol {
|
||||
pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self {
|
||||
pub fn new(declared_name: &str, is_mutable: bool, identifier: Option<&Identifier>) -> Self {
|
||||
VariableSymbol {
|
||||
name: name.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
is_mutable,
|
||||
definition,
|
||||
definition: identifier.map(SourceDefinition::from_identifier),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SymbolInner for VariableSymbol {
|
||||
fn declared_name(&self) -> &str {
|
||||
self.declared_name.as_str()
|
||||
}
|
||||
|
||||
pub fn definition(&self) -> &SourceDefinition {
|
||||
&self.definition
|
||||
fn definition(&self) -> Option<SourceDefinition> {
|
||||
self.definition.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,45 +363,7 @@ impl Display for VariableSymbol {
|
||||
write!(
|
||||
f,
|
||||
"VariableSymbol(name = {}, is_mutable = {})",
|
||||
self.name, self.is_mutable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ModuleSymbol {
|
||||
pub fqn: String,
|
||||
pub declared_name: String,
|
||||
pub is_public: bool,
|
||||
definition: SourceDefinition,
|
||||
}
|
||||
|
||||
impl ModuleSymbol {
|
||||
pub fn new(
|
||||
fqn: &str,
|
||||
declared_name: &str,
|
||||
is_public: bool,
|
||||
identifier: &Identifier,
|
||||
) -> ModuleSymbol {
|
||||
ModuleSymbol {
|
||||
fqn: fqn.to_string(),
|
||||
declared_name: declared_name.to_string(),
|
||||
is_public,
|
||||
definition: SourceDefinition::from_identifier(identifier),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn definition(&self) -> &SourceDefinition {
|
||||
&self.definition
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ModuleSymbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ModuleSymbol(name = {}, is_public = {})",
|
||||
self.fqn, self.is_public
|
||||
self.declared_name, self.is_mutable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,24 @@
|
||||
use crate::name_analysis::symbol::Symbol;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::cell::RefCell;
|
||||
use crate::name_analysis::symbol::{
|
||||
FunctionSymbol, ModuleSymbol, ParameterSymbol, Symbol, SymbolInner, TypeSymbol,
|
||||
UseStatementSymbol, VariableSymbol,
|
||||
};
|
||||
use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined;
|
||||
use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
/* Scope */
|
||||
|
||||
pub struct Scope {
|
||||
#[derive(Debug)]
|
||||
struct Scope {
|
||||
parent: Option<usize>,
|
||||
function_and_variable_symbols: HashMap<String, Symbol>,
|
||||
type_and_module_symbols: HashMap<String, Symbol>,
|
||||
use_statement_symbols: HashMap<String, Rc<RefCell<UseStatementSymbol>>>,
|
||||
module_symbols: HashMap<String, Rc<ModuleSymbol>>,
|
||||
type_symbols: HashMap<String, Rc<TypeSymbol>>,
|
||||
function_symbols: HashMap<String, Rc<FunctionSymbol>>,
|
||||
parameter_symbols: HashMap<String, Rc<ParameterSymbol>>,
|
||||
variable_symbols: HashMap<String, Rc<VariableSymbol>>,
|
||||
debug_name: String,
|
||||
}
|
||||
|
||||
@ -15,21 +26,91 @@ impl Scope {
|
||||
pub fn new(parent: Option<usize>, debug_name: String) -> Scope {
|
||||
Scope {
|
||||
parent,
|
||||
function_and_variable_symbols: HashMap::new(),
|
||||
type_and_module_symbols: HashMap::new(),
|
||||
use_statement_symbols: HashMap::new(),
|
||||
module_symbols: HashMap::new(),
|
||||
type_symbols: HashMap::new(),
|
||||
function_symbols: HashMap::new(),
|
||||
parameter_symbols: HashMap::new(),
|
||||
variable_symbols: HashMap::new(),
|
||||
debug_name,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_any_symbol(&self, name: &str) -> Option<Symbol> {
|
||||
self.variable_symbols.get(name)
|
||||
.map(|s| Symbol::Variable(s.clone()))
|
||||
.or_else(|| self.parameter_symbols.get(name).map(|s| Symbol::Parameter(s.clone())))
|
||||
.or_else(|| self.function_symbols.get(name).map(|s| Symbol::Function(s.clone())))
|
||||
.or_else(|| self.type_symbols.get(name).map(|ts| Symbol::Type(ts.clone())))
|
||||
.or_else(|| self.module_symbols.get(name).map(|ms| Symbol::Module(ms.clone())))
|
||||
.or_else(|| self.use_statement_symbols.get(name).map(|us| Symbol::UseStatement(us.clone())))
|
||||
}
|
||||
|
||||
fn get_module_symbol_by_declared_name(&self, name: &str) -> Option<Rc<ModuleSymbol>> {
|
||||
for module_symbol in self.module_symbols.values() {
|
||||
if module_symbol.declared_name() == name {
|
||||
return Some(module_symbol.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_usable_symbol_by_fqn(&self, fqn: &str) -> Option<Symbol> {
|
||||
for function_symbol in self.function_symbols.values() {
|
||||
if function_symbol.fqn() == fqn {
|
||||
return Some(Symbol::Function(function_symbol.clone()));
|
||||
}
|
||||
}
|
||||
for type_symbol in self.type_symbols.values() {
|
||||
if type_symbol.fqn() == fqn {
|
||||
return Some(Symbol::Type(type_symbol.clone()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_usable_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> {
|
||||
for function_symbol in self.function_symbols.values() {
|
||||
if function_symbol.declared_name() == declared_name {
|
||||
return Some(Symbol::Function(function_symbol.clone()));
|
||||
}
|
||||
}
|
||||
for type_symbol in self.type_symbols.values() {
|
||||
if type_symbol.declared_name() == declared_name {
|
||||
return Some(Symbol::Type(type_symbol.clone()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_value_symbol_by_declared_name(&self, declared_name: &str) -> Option<Symbol> {
|
||||
for variable_symbol in self.variable_symbols.values() {
|
||||
if variable_symbol.declared_name() == declared_name {
|
||||
return Some(Symbol::Variable(variable_symbol.clone()));
|
||||
}
|
||||
}
|
||||
for parameter_symbol in self.parameter_symbols.values() {
|
||||
if parameter_symbol.declared_name() == declared_name {
|
||||
return Some(Symbol::Parameter(parameter_symbol.clone()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/* Symbol table */
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymbolInsertError {
|
||||
SymbolAlreadyDefined(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SymbolLookupError {
|
||||
NoDefinition
|
||||
NoDefinition,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SymbolTable {
|
||||
scopes: Vec<Scope>,
|
||||
current_scope_id: usize,
|
||||
@ -49,10 +130,16 @@ impl SymbolTable {
|
||||
self.current_scope_id
|
||||
}
|
||||
|
||||
pub fn scopes(&self) -> &Vec<Scope> {
|
||||
&self.scopes
|
||||
}
|
||||
|
||||
pub fn push_scope(&mut self, debug_name: &str) {
|
||||
let id = self.scopes.len();
|
||||
self.scopes
|
||||
.push(Scope::new(Some(self.current_scope_id), debug_name.to_string()));
|
||||
self.scopes.push(Scope::new(
|
||||
Some(self.current_scope_id),
|
||||
debug_name.to_string(),
|
||||
));
|
||||
self.current_scope_id = id;
|
||||
}
|
||||
|
||||
@ -62,47 +149,115 @@ impl SymbolTable {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> {
|
||||
match symbol {
|
||||
Symbol::Function(_) | Symbol::Variable(_) => {
|
||||
self.insert_function_or_variable(name, symbol)
|
||||
}
|
||||
Symbol::Module(_) => self.insert_module_or_type(name, symbol),
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_function_or_variable(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> {
|
||||
if let Some(defined_symbol) = self.scopes[self.current_scope_id]
|
||||
.function_and_variable_symbols
|
||||
.get(name)
|
||||
pub fn insert_use_statement_symbol(
|
||||
&mut self,
|
||||
use_statement_symbol: UseStatementSymbol,
|
||||
) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_usable_symbol_by_declared_name(use_statement_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol.clone()))
|
||||
Err(SymbolAlreadyDefined(defined_symbol))
|
||||
} else {
|
||||
self.scopes[self.current_scope_id]
|
||||
.function_and_variable_symbols
|
||||
.insert(name.to_string(), symbol);
|
||||
current_scope.use_statement_symbols.insert(
|
||||
use_statement_symbol.declared_name().to_string(),
|
||||
Rc::new(RefCell::new(use_statement_symbol)),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_module_or_type(&mut self, name: &str, symbol: Symbol) -> Result<(), SymbolInsertError> {
|
||||
if let Some(defined_symbol) = self.scopes[self.current_scope_id]
|
||||
.type_and_module_symbols
|
||||
.get(name)
|
||||
pub fn insert_module_symbol(
|
||||
&mut self,
|
||||
module_symbol: ModuleSymbol,
|
||||
) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_module_symbol_by_declared_name(module_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol.clone()))
|
||||
Err(SymbolAlreadyDefined(Symbol::Module(defined_symbol.clone())))
|
||||
} else {
|
||||
self.scopes[self.current_scope_id]
|
||||
.type_and_module_symbols
|
||||
.insert(name.to_string(), symbol);
|
||||
current_scope.module_symbols.insert(
|
||||
module_symbol.declared_name().to_string(),
|
||||
Rc::new(module_symbol),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, SymbolLookupError> {
|
||||
pub fn insert_type_symbol(&mut self, type_symbol: TypeSymbol) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_usable_symbol_by_declared_name(type_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol))
|
||||
} else {
|
||||
current_scope.type_symbols.insert(
|
||||
type_symbol.declared_name().to_string(),
|
||||
Rc::new(type_symbol),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_function_symbol(
|
||||
&mut self,
|
||||
function_symbol: FunctionSymbol,
|
||||
) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_usable_symbol_by_declared_name(function_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol))
|
||||
} else {
|
||||
current_scope.function_symbols.insert(
|
||||
function_symbol.declared_name().to_string(),
|
||||
Rc::new(function_symbol),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_parameter_symbol(
|
||||
&mut self,
|
||||
parameter_symbol: ParameterSymbol,
|
||||
) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_value_symbol_by_declared_name(parameter_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol))
|
||||
} else {
|
||||
current_scope.parameter_symbols.insert(
|
||||
parameter_symbol.declared_name().to_string(),
|
||||
Rc::new(parameter_symbol),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_variable_symbol(
|
||||
&mut self,
|
||||
variable_symbol: VariableSymbol,
|
||||
) -> Result<(), SymbolInsertError> {
|
||||
let current_scope = self.scopes.get_mut(self.current_scope_id).unwrap();
|
||||
if let Some(defined_symbol) =
|
||||
current_scope.get_value_symbol_by_declared_name(variable_symbol.declared_name())
|
||||
{
|
||||
Err(SymbolAlreadyDefined(defined_symbol))
|
||||
} else {
|
||||
current_scope.variable_symbols.insert(
|
||||
variable_symbol.declared_name().to_string(),
|
||||
Rc::new(variable_symbol),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup(&self, name: &str, scope_id: usize) -> Result<Symbol, SymbolLookupError> {
|
||||
let mut scope_opt = Some(&self.scopes[scope_id]);
|
||||
while let Some(scope) = scope_opt {
|
||||
if let Some(symbol) = scope.function_and_variable_symbols.get(name) {
|
||||
if let Some(symbol) = scope.get_any_symbol(name) {
|
||||
return Ok(symbol);
|
||||
}
|
||||
scope_opt = if let Some(parent_id) = scope.parent {
|
||||
@ -113,6 +268,19 @@ impl SymbolTable {
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
|
||||
pub fn lookup_usable_by_fqn(
|
||||
&self,
|
||||
fully_qualified_name: &str,
|
||||
scope_id: usize,
|
||||
) -> Result<Symbol, SymbolLookupError> {
|
||||
for scope in &self.scopes {
|
||||
if let Some(symbol) = scope.get_usable_symbol_by_fqn(fully_qualified_name) {
|
||||
return Ok(symbol);
|
||||
}
|
||||
}
|
||||
Err(NoDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SymbolTable {
|
||||
@ -120,7 +288,19 @@ impl Display for SymbolTable {
|
||||
writeln!(f, "SymbolTable(current_scope = {})", self.current_scope_id)?;
|
||||
for (i, scope) in self.scopes.iter().enumerate() {
|
||||
writeln!(f, "Scope {} {}", i, scope.debug_name)?;
|
||||
for (name, symbol) in &scope.function_and_variable_symbols {
|
||||
for (name, symbol) in &scope.use_statement_symbols {
|
||||
writeln!(f, " {}({})", name, symbol.borrow())?;
|
||||
}
|
||||
for (name, symbol) in &scope.module_symbols {
|
||||
writeln!(f, " {}({})", name, symbol)?;
|
||||
}
|
||||
for (name, symbol) in &scope.type_symbols {
|
||||
writeln!(f, " {}({})", name, symbol)?;
|
||||
}
|
||||
for (name, symbol) in &scope.function_symbols {
|
||||
writeln!(f, " {}({})", name, symbol)?;
|
||||
}
|
||||
for (name, symbol) in &scope.variable_symbols {
|
||||
writeln!(f, " {}({})", name, symbol)?;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
@ -382,6 +385,7 @@ PlatformFunction = {
|
||||
~ Identifier
|
||||
~ Parameters
|
||||
~ ReturnType
|
||||
~ ";"
|
||||
}
|
||||
|
||||
InterfaceFunction = {
|
||||
@ -479,6 +483,20 @@ Field = {
|
||||
|
||||
// Statements
|
||||
|
||||
UseStatement = {
|
||||
Use
|
||||
~ Identifier
|
||||
~ ( "::" ~ Identifier )*
|
||||
~ ( "::" ~ ( Star | UseList ) )?
|
||||
}
|
||||
|
||||
UseList = {
|
||||
"{"
|
||||
~ Identifier
|
||||
~ ( "," ~ Identifier )*
|
||||
~ "}"
|
||||
}
|
||||
|
||||
BlockStatement = {
|
||||
"{"
|
||||
~ Statement*
|
||||
@ -492,6 +510,7 @@ Statement = {
|
||||
| AssignmentStatement
|
||||
| CallStatement
|
||||
| ReturnStatement
|
||||
| UseStatement
|
||||
)
|
||||
~ Semicolon
|
||||
| (
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
23
src/std_core/mod.rs
Normal file
23
src/std_core/mod.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::name_analysis::symbol::{FunctionSymbol, TypeSymbol};
|
||||
use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable};
|
||||
|
||||
pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), SymbolInsertError> {
|
||||
symbol_table.insert_type_symbol(TypeSymbol::new("std::core:Array", "Array", true, None))?;
|
||||
// todo: make this primitive
|
||||
symbol_table.insert_type_symbol(TypeSymbol::new("std::core::String", "String", true, None))?;
|
||||
symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
"std::core::println",
|
||||
"println",
|
||||
true,
|
||||
true,
|
||||
None,
|
||||
))?;
|
||||
symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||
"std::core::print",
|
||||
"print",
|
||||
true,
|
||||
true,
|
||||
None,
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user