Add codespan-reporting to project for awesome error reporting.
This commit is contained in:
parent
2b4e042602
commit
6ab9efa8fd
56
Cargo.lock
generated
56
Cargo.lock
generated
@ -106,6 +106,17 @@ version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
@ -136,6 +147,7 @@ name = "deimos"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
]
|
||||
@ -253,6 +265,26 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
@ -281,6 +313,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@ -319,6 +360,12 @@ version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
@ -331,6 +378,15 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
@ -15,3 +15,4 @@ path = "src/bin/dmc/main.rs"
|
||||
pest = "2.7.14"
|
||||
clap = { version = "4.5.23", features = ["derive"] }
|
||||
pest_derive = "2.7.14"
|
||||
codespan-reporting = "0.12.0"
|
||||
|
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
@ -4,7 +4,10 @@ fn main() {
|
||||
let x = 'Hello';
|
||||
let y = 'World';
|
||||
{
|
||||
let x = 'Hello';
|
||||
let test = 'Test';
|
||||
let test = 'Again';
|
||||
};
|
||||
x = y;
|
||||
let x = 'Hello!';
|
||||
}
|
@ -14,10 +14,18 @@ pub fn build_ast(compilation_unit_pair: Pair<Rule>) -> CompilationUnit {
|
||||
}
|
||||
|
||||
fn build_identifier(identifier_pair: Pair<Rule>) -> Identifier {
|
||||
Identifier::new(identifier_pair.as_span().as_str())
|
||||
let as_span = identifier_pair.as_span();
|
||||
Identifier::new(
|
||||
as_span.as_str(),
|
||||
Range {
|
||||
start: as_span.start(),
|
||||
end: as_span.end(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn build_fqn(fqn_pair: Pair<Rule>) -> FullyQualifiedName {
|
||||
let as_span = fqn_pair.as_span();
|
||||
FullyQualifiedName::new(
|
||||
fqn_pair
|
||||
.into_inner()
|
||||
@ -25,6 +33,10 @@ fn build_fqn(fqn_pair: Pair<Rule>) -> FullyQualifiedName {
|
||||
expect_and_use(identifier_pair, Rule::Identifier, build_identifier)
|
||||
})
|
||||
.collect(),
|
||||
Range {
|
||||
start: as_span.start(),
|
||||
end: as_span.end(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::compile::name_analysis::Symbol;
|
||||
use pest::Parser;
|
||||
use std::range::Range;
|
||||
|
||||
pub mod build;
|
||||
pub mod named;
|
||||
@ -54,14 +55,16 @@ pub enum SuffixUnaryOperator {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Identifier {
|
||||
pub name: String,
|
||||
pub range: Range<usize>,
|
||||
scope_id: Option<usize>,
|
||||
symbol: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl Identifier {
|
||||
pub fn new(name: &str) -> Self {
|
||||
pub fn new(name: &str, range: Range<usize>) -> Self {
|
||||
Identifier {
|
||||
name: name.to_string(),
|
||||
range,
|
||||
scope_id: None,
|
||||
symbol: None,
|
||||
}
|
||||
@ -87,14 +90,16 @@ impl Identifier {
|
||||
#[derive(Debug)]
|
||||
pub struct FullyQualifiedName {
|
||||
pub identifiers: Vec<Identifier>,
|
||||
pub range: Range<usize>,
|
||||
scope_id: Option<usize>,
|
||||
symbol: Option<Symbol>,
|
||||
}
|
||||
|
||||
impl FullyQualifiedName {
|
||||
pub fn new(identifiers: Vec<Identifier>) -> Self {
|
||||
pub fn new(identifiers: Vec<Identifier>, range: Range<usize>) -> Self {
|
||||
FullyQualifiedName {
|
||||
identifiers,
|
||||
range,
|
||||
scope_id: None,
|
||||
symbol: None,
|
||||
}
|
||||
|
@ -46,7 +46,10 @@ fn main() {
|
||||
}
|
||||
Commands::NameAnalysis { paths } => {
|
||||
for path in paths {
|
||||
name_analysis(&path)
|
||||
let result = name_analysis(&path);
|
||||
if let Err(e) = result {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,37 @@
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||
use deimos::ast::build::build_ast;
|
||||
use deimos::compile::name_analysis::{analyze_names, SymbolTable};
|
||||
use deimos::parser::{DeimosParser, Rule};
|
||||
use pest::Parser;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn name_analysis(path: &Path) {
|
||||
pub fn name_analysis(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let src = std::fs::read_to_string(path).unwrap();
|
||||
let parse_result = DeimosParser::parse(
|
||||
Rule::CompilationUnit,
|
||||
&src
|
||||
);
|
||||
let parse_result = DeimosParser::parse(Rule::CompilationUnit, &src);
|
||||
let mut files = SimpleFiles::new();
|
||||
let file_id = files.add(path.display().to_string(), &src);
|
||||
|
||||
match parse_result {
|
||||
Ok(mut pairs) => {
|
||||
let compilation_unit_pair = pairs.next().unwrap();
|
||||
let mut compilation_unit = build_ast(compilation_unit_pair);
|
||||
let mut symbol_table = SymbolTable::new();
|
||||
let name_analysis_result = analyze_names(
|
||||
&mut compilation_unit,
|
||||
&mut symbol_table,
|
||||
);
|
||||
match name_analysis_result {
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
Ok(_) => {
|
||||
println!("name_analysis complete");
|
||||
println!("{}", symbol_table);
|
||||
let diagnostics = analyze_names(file_id, &mut compilation_unit, &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) => {
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use crate::ast::named::Named;
|
||||
use crate::ast::*;
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
|
||||
@ -9,6 +10,15 @@ pub enum Symbol {
|
||||
Variable(VariableSymbol),
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Symbol::Function(s) => s.declared_name.as_str(),
|
||||
Symbol::Variable(s) => s.name.as_str(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Symbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use Symbol::*;
|
||||
@ -96,7 +106,10 @@ impl SymbolTable {
|
||||
|
||||
pub fn insert(&mut self, name: String, symbol: Symbol) -> Result<(), String> {
|
||||
if let Some(current_symbol) = self.scopes[self.current_scope_id].symbols.get(&name) {
|
||||
Err(format!("Symbol '{}' already defined", current_symbol))
|
||||
Err(format!(
|
||||
"Symbol '{}' already defined in current scope.",
|
||||
current_symbol.name()
|
||||
))
|
||||
} else {
|
||||
self.scopes[self.current_scope_id]
|
||||
.symbols
|
||||
@ -117,7 +130,7 @@ impl SymbolTable {
|
||||
None
|
||||
};
|
||||
}
|
||||
Err(format!("Symbol '{}' not found", name))
|
||||
Err(format!("Symbol '{}' not found in current scope.", name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,101 +186,138 @@ impl FqnContext {
|
||||
}
|
||||
|
||||
pub fn analyze_names(
|
||||
file_id: usize,
|
||||
compilation_unit: &mut CompilationUnit,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let mut fqn_context = FqnContext::new();
|
||||
if let Some(namespace) = &compilation_unit.namespace {
|
||||
fqn_context.push(namespace.name().to_string());
|
||||
}
|
||||
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
gather_module_level_declaration(declaration, symbol_table, &mut fqn_context)?;
|
||||
diagnostics.extend(gather_module_level_declaration(
|
||||
file_id,
|
||||
declaration,
|
||||
symbol_table,
|
||||
&mut fqn_context,
|
||||
));
|
||||
}
|
||||
|
||||
assert_eq!(symbol_table.current_scope_id, 0);
|
||||
|
||||
for declaration in &mut compilation_unit.declarations {
|
||||
resolve_module_level_declaration(declaration, symbol_table)?;
|
||||
diagnostics.extend(resolve_module_level_declaration(file_id, declaration, symbol_table));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn gather_module_level_declaration(
|
||||
file_id: usize,
|
||||
declaration: &mut ModuleLevelDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use ModuleLevelDeclaration::*;
|
||||
match declaration {
|
||||
Function(function_definition) => {
|
||||
gather_function_definition(function_definition, symbol_table, fqn_context)
|
||||
gather_function_definition(file_id, function_definition, symbol_table, fqn_context)
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_function_definition(
|
||||
file_id: usize,
|
||||
function: &mut FunctionDefinition,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
let declared_name = function.identifier.name().to_string();
|
||||
let resolved_name = fqn_context.resolve(&declared_name);
|
||||
symbol_table.insert(
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
declared_name.clone(),
|
||||
Symbol::Function(FunctionSymbol {
|
||||
fqn: resolved_name.clone(),
|
||||
declared_name,
|
||||
is_public: function.is_public,
|
||||
}),
|
||||
)?;
|
||||
);
|
||||
if let Err(msg) = insert_result {
|
||||
diagnostics.push(
|
||||
Diagnostic::error()
|
||||
.with_message(msg)
|
||||
.with_label(Label::primary(file_id, function.identifier.range)),
|
||||
)
|
||||
}
|
||||
|
||||
function
|
||||
.identifier
|
||||
.set_scope_id(symbol_table.current_scope_id());
|
||||
|
||||
symbol_table.push_scope(&format!("FunctionScope({})", resolved_name));
|
||||
// TODO: params
|
||||
gather_function_body(&mut function.body, symbol_table, fqn_context)?;
|
||||
diagnostics.extend(gather_function_body(
|
||||
file_id,
|
||||
&mut function.body,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
));
|
||||
symbol_table.pop_scope();
|
||||
Ok(())
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn gather_function_body(
|
||||
file_id: usize,
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use FunctionBody::*;
|
||||
match function_body {
|
||||
Block(block) => gather_block_statement(block, symbol_table, fqn_context),
|
||||
Block(block) => gather_block_statement(file_id, block, symbol_table, fqn_context),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_block_statement(
|
||||
file_id: usize,
|
||||
block: &mut BlockStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
symbol_table.push_scope("BlockStatementScope");
|
||||
for statement in &mut block.statements {
|
||||
gather_statement(statement, symbol_table, fqn_context)?;
|
||||
diagnostics.extend(gather_statement(
|
||||
file_id,
|
||||
statement,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
));
|
||||
}
|
||||
symbol_table.pop_scope();
|
||||
Ok(())
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn gather_statement(
|
||||
file_id: usize,
|
||||
statement: &mut Statement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use Statement::*;
|
||||
match statement {
|
||||
BlockStatement(block) => gather_block_statement(block, symbol_table, fqn_context),
|
||||
BlockStatement(block) => gather_block_statement(file_id, block, symbol_table, fqn_context),
|
||||
VariableDeclarationStatement(variable_declaration) => {
|
||||
gather_variable_declaration(variable_declaration, symbol_table, fqn_context)
|
||||
gather_variable_declaration(file_id, variable_declaration, symbol_table)
|
||||
}
|
||||
AssignStatement(assign_statement) => {
|
||||
gather_assign_statement(assign_statement, symbol_table, fqn_context)
|
||||
@ -277,162 +327,198 @@ fn gather_statement(
|
||||
}
|
||||
|
||||
fn gather_variable_declaration(
|
||||
file_id: usize,
|
||||
variable_declaration: &mut VariableDeclarationStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
let variable_name = variable_declaration.identifier.name().to_string();
|
||||
symbol_table.insert(
|
||||
|
||||
let insert_result = symbol_table.insert(
|
||||
variable_name.clone(),
|
||||
Symbol::Variable(VariableSymbol {
|
||||
name: variable_name,
|
||||
is_mutable: variable_declaration.is_mutable,
|
||||
}),
|
||||
)?;
|
||||
);
|
||||
|
||||
if let Err(msg) = insert_result {
|
||||
diagnostics.push(
|
||||
Diagnostic::error()
|
||||
.with_message(msg)
|
||||
.with_label(Label::primary(
|
||||
file_id,
|
||||
variable_declaration.identifier.range,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
variable_declaration
|
||||
.identifier
|
||||
.set_scope_id(symbol_table.current_scope_id());
|
||||
Ok(())
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn gather_assign_statement(
|
||||
assign_statement: &mut AssignStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
gather_expression(&mut assign_statement.lhs, symbol_table, fqn_context)?;
|
||||
gather_expression(&mut assign_statement.rhs, symbol_table, fqn_context)?;
|
||||
Ok(())
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.extend(gather_expression(
|
||||
&mut assign_statement.lhs,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
));
|
||||
diagnostics.extend(gather_expression(
|
||||
&mut assign_statement.rhs,
|
||||
symbol_table,
|
||||
fqn_context,
|
||||
));
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn gather_expression(
|
||||
expression: &mut Expression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use Expression::*;
|
||||
match expression {
|
||||
FullyQualifiedName(fully_qualified_name) => {
|
||||
gather_fully_qualified_name(fully_qualified_name, symbol_table, fqn_context)?;
|
||||
gather_fully_qualified_name(fully_qualified_name, symbol_table)
|
||||
}
|
||||
_ => {
|
||||
vec![]
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gather_fully_qualified_name(
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
symbol_table: &mut SymbolTable,
|
||||
fqn_context: &mut FqnContext,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
fully_qualified_name.set_scope_id(symbol_table.current_scope_id());
|
||||
Ok(())
|
||||
vec![]
|
||||
}
|
||||
|
||||
/* Resolve */
|
||||
|
||||
fn resolve_module_level_declaration(
|
||||
file_id: usize,
|
||||
declaration: &mut ModuleLevelDeclaration,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use ModuleLevelDeclaration::*;
|
||||
match declaration {
|
||||
Function(function_definition) => {
|
||||
resolve_function_definition(function_definition, symbol_table)
|
||||
resolve_function_definition(file_id, function_definition, symbol_table)
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_function_definition(
|
||||
file_id: usize,
|
||||
function_definition: &mut FunctionDefinition,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
resolve_function_body(&mut function_definition.body, symbol_table)
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
resolve_function_body(file_id, &mut function_definition.body, symbol_table)
|
||||
}
|
||||
|
||||
fn resolve_function_body(
|
||||
file_id: usize,
|
||||
function_body: &mut FunctionBody,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use FunctionBody::*;
|
||||
match function_body {
|
||||
Block(block) => resolve_block(block, symbol_table),
|
||||
Block(block) => resolve_block(file_id, block, symbol_table),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_block(
|
||||
file_id: usize,
|
||||
block_statement: &mut BlockStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
for statement in &mut block_statement.statements {
|
||||
resolve_statement(statement, symbol_table)?;
|
||||
}
|
||||
Ok(())
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
block_statement
|
||||
.statements
|
||||
.iter_mut()
|
||||
.flat_map(|statement| resolve_statement(file_id, statement, symbol_table))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn resolve_statement(
|
||||
file_id: usize,
|
||||
statement: &mut Statement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use Statement::*;
|
||||
match statement {
|
||||
BlockStatement(block) => resolve_block(block, symbol_table),
|
||||
BlockStatement(block) => resolve_block(file_id, block, symbol_table),
|
||||
VariableDeclarationStatement(variable_declaration) => {
|
||||
resolve_variable_declaration(variable_declaration, symbol_table)
|
||||
resolve_variable_declaration(file_id, variable_declaration, symbol_table)
|
||||
}
|
||||
AssignStatement(assign_statement) => {
|
||||
resolve_assign_statement(assign_statement, symbol_table)
|
||||
resolve_assign_statement(file_id, assign_statement, symbol_table)
|
||||
}
|
||||
CallStatement(call_statement) => resolve_call_statement(call_statement, symbol_table),
|
||||
CallStatement(call_statement) => resolve_call_statement(file_id, call_statement, symbol_table),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_variable_declaration(
|
||||
file_id: usize,
|
||||
variable_declaration: &mut VariableDeclarationStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
if let Some(initializer) = &mut variable_declaration.initializer {
|
||||
resolve_expression(initializer, symbol_table)
|
||||
resolve_expression(file_id, initializer, symbol_table)
|
||||
} else {
|
||||
Ok(())
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_assign_statement(
|
||||
file_id: usize,
|
||||
assign_statement: &mut AssignStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
resolve_expression(&mut assign_statement.lhs, symbol_table)?;
|
||||
resolve_expression(&mut assign_statement.rhs, symbol_table)?;
|
||||
Ok(())
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let mut diagnostics = vec![];
|
||||
diagnostics.extend(resolve_expression(file_id, &mut assign_statement.lhs, symbol_table));
|
||||
diagnostics.extend(resolve_expression(file_id, &mut assign_statement.rhs, symbol_table));
|
||||
diagnostics
|
||||
}
|
||||
|
||||
fn resolve_call_statement(
|
||||
file_id: usize,
|
||||
call_statement: &mut CallStatement,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
resolve_expression(&mut call_statement.0, symbol_table)
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
resolve_expression(file_id, &mut call_statement.0, symbol_table)
|
||||
}
|
||||
|
||||
fn resolve_expression(
|
||||
file_id: usize,
|
||||
expression: &mut Expression,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
use Expression::*;
|
||||
match expression {
|
||||
FullyQualifiedName(fqn) => resolve_fully_qualified_name(fqn, symbol_table),
|
||||
Literal(_) => Ok(()),
|
||||
FullyQualifiedName(fqn) => resolve_fully_qualified_name(file_id, fqn, symbol_table),
|
||||
Literal(_) => vec![],
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_fully_qualified_name(
|
||||
file_id: usize,
|
||||
fully_qualified_name: &mut FullyQualifiedName,
|
||||
symbol_table: &mut SymbolTable,
|
||||
) -> Result<(), String> {
|
||||
) -> Vec<Diagnostic<usize>> {
|
||||
let lookup_result = symbol_table.lookup(
|
||||
fully_qualified_name.name().as_ref(),
|
||||
fully_qualified_name.scope_id().expect(&format!(
|
||||
@ -443,8 +529,12 @@ fn resolve_fully_qualified_name(
|
||||
match lookup_result {
|
||||
Ok(symbol) => {
|
||||
fully_qualified_name.set_symbol(symbol.clone());
|
||||
Ok(())
|
||||
vec![]
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Err(e) => vec![
|
||||
Diagnostic::error()
|
||||
.with_message(e)
|
||||
.with_label(Label::primary(file_id, fully_qualified_name.range))
|
||||
],
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![feature(new_range_api)]
|
||||
#![allow(warnings)]
|
||||
pub mod ast;
|
||||
pub mod compile;
|
||||
|
Loading…
Reference in New Issue
Block a user