diff --git a/Cargo.lock b/Cargo.lock index 3ae2be0..d21f4a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,7 @@ version = "0.1.0" dependencies = [ "clap", "codespan-reporting", + "log", "pest", "pest_derive", ] @@ -190,6 +191,12 @@ version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + [[package]] name = "memchr" version = "2.7.4" diff --git a/Cargo.toml b/Cargo.toml index a1d1c76..e4ebad0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ pest = "2.7.14" clap = { version = "4.5.23", features = ["derive"] } pest_derive = "2.7.14" codespan-reporting = "0.12.0" +log = "0.4.27" diff --git a/sketching/may_2025/name_one.dm b/sketching/may_2025/name_one.dm index c94a645..67ad445 100644 --- a/sketching/may_2025/name_one.dm +++ b/sketching/may_2025/name_one.dm @@ -1,13 +1,13 @@ ns greeter -fn main() { +fn main(x: String) { let x = 'Hello'; let y = 'World'; { - let x = 'Hello'; - let test = 'Test'; - let test = 'Again'; + let test = 'test'; + let x = 'x'; + let y = 'y'; + let z = 'z'; + let test = 'oops.'; }; - x = y; - let x = 'Hello!'; } \ No newline at end of file diff --git a/src/ast/build.rs b/src/ast/build.rs index a4acfc7..164cabd 100644 --- a/src/ast/build.rs +++ b/src/ast/build.rs @@ -2,21 +2,27 @@ use crate::ast::*; use crate::parser::Rule; use pest::iterators::{Pair, Pairs}; -fn expect_and_use(pair: Pair, rule: Rule, f: fn(Pair) -> T) -> T { +fn expect_and_use( + file_id: usize, + pair: Pair, + rule: Rule, + f: fn(usize, Pair) -> T, +) -> T { if pair.as_rule() != rule { panic!("Expected rule {:?} but found {:?}", rule, pair.as_rule()) } - f(pair) + f(file_id, pair) } -pub fn build_ast(compilation_unit_pair: Pair) -> CompilationUnit { - build_compilation_unit(compilation_unit_pair) +pub fn build_ast(file_id: usize, compilation_unit_pair: Pair) -> CompilationUnit { + build_compilation_unit(file_id, compilation_unit_pair) } -fn build_identifier(identifier_pair: Pair) -> Identifier { +fn build_identifier(file_id: usize, identifier_pair: Pair) -> Identifier { let as_span = identifier_pair.as_span(); Identifier::new( as_span.as_str(), + file_id, Range { start: as_span.start(), end: as_span.end(), @@ -24,15 +30,16 @@ fn build_identifier(identifier_pair: Pair) -> Identifier { ) } -fn build_fqn(fqn_pair: Pair) -> FullyQualifiedName { +fn build_fqn(file_id: usize, fqn_pair: Pair) -> FullyQualifiedName { let as_span = fqn_pair.as_span(); FullyQualifiedName::new( fqn_pair .into_inner() .map(|identifier_pair| { - expect_and_use(identifier_pair, Rule::Identifier, build_identifier) + expect_and_use(file_id, identifier_pair, Rule::Identifier, build_identifier) }) .collect(), + file_id, Range { start: as_span.start(), end: as_span.end(), @@ -40,20 +47,20 @@ fn build_fqn(fqn_pair: Pair) -> FullyQualifiedName { ) } -fn build_type_use(type_use_pair: Pair) -> TypeUse { +fn build_type_use(file_id: usize, type_use_pair: Pair) -> TypeUse { let inner_pair = type_use_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { Rule::Void => TypeUse::Void, Rule::InterfaceOrClassTypeUse => { - TypeUse::InterfaceOrClass(build_interface_or_class_type_use(inner_pair)) + TypeUse::InterfaceOrClass(build_interface_or_class_type_use(file_id, inner_pair)) } - Rule::TupleTypeUse => TypeUse::Tuple(build_tuple_type_use(inner_pair)), - Rule::FunctionTypeUse => TypeUse::Function(build_function_type_use(inner_pair)), + Rule::TupleTypeUse => TypeUse::Tuple(build_tuple_type_use(file_id, inner_pair)), + Rule::FunctionTypeUse => TypeUse::Function(build_function_type_use(file_id, inner_pair)), _ => unreachable!(), } } -fn build_interface_or_class_type_use(pair: Pair) -> InterfaceOrClassTypeUse { +fn build_interface_or_class_type_use(file_id: usize, pair: Pair) -> InterfaceOrClassTypeUse { let mut borrow_count = 0; let mut is_mutable = false; let mut fqn = None; @@ -68,10 +75,10 @@ fn build_interface_or_class_type_use(pair: Pair) -> InterfaceOrClassTypeUs is_mutable = true; } Rule::FullyQualifiedName => { - fqn = Some(build_fqn(inner_pair)); + fqn = Some(build_fqn(file_id, inner_pair)); } Rule::GenericArguments => { - generic_arguments = build_generic_arguments(inner_pair); + generic_arguments = build_generic_arguments(file_id, inner_pair); } _ => unreachable!(), } @@ -85,7 +92,7 @@ fn build_interface_or_class_type_use(pair: Pair) -> InterfaceOrClassTypeUs } } -fn build_tuple_type_use(tuple_type_use_pair: Pair) -> TupleTypeUse { +fn build_tuple_type_use(file_id: usize, tuple_type_use_pair: Pair) -> TupleTypeUse { let mut borrow_count = 0; let mut is_mutable = false; let mut arguments = None; @@ -99,7 +106,7 @@ fn build_tuple_type_use(tuple_type_use_pair: Pair) -> TupleTypeUse { is_mutable = true; } Rule::TupleArguments => { - arguments = Some(build_tuple_arguments(inner_pair)); + arguments = Some(build_tuple_arguments(file_id, inner_pair)); } _ => unreachable!(), } @@ -112,7 +119,7 @@ fn build_tuple_type_use(tuple_type_use_pair: Pair) -> TupleTypeUse { } } -fn build_function_type_use(function_pair: Pair) -> FunctionTypeUse { +fn build_function_type_use(file_id: usize, function_pair: Pair) -> FunctionTypeUse { let mut borrow_count = 0; let mut function_modifier: Option = None; let mut generics = GenericParameters::default(); @@ -125,17 +132,17 @@ fn build_function_type_use(function_pair: Pair) -> FunctionTypeUse { borrow_count += 1; } Rule::FunctionTypeModifier => { - function_modifier = Some(build_function_type_modifier(inner_pair)); + function_modifier = Some(build_function_type_modifier(file_id, inner_pair)); } Rule::Fn => {} Rule::GenericParameters => { - generics = build_generic_parameters(inner_pair); + generics = build_generic_parameters(file_id, inner_pair); } Rule::Parameters => { - parameters = Some(build_parameters(inner_pair)); + parameters = Some(build_parameters(file_id, inner_pair)); } Rule::ReturnType => { - return_type = Some(build_return_type(inner_pair)); + return_type = Some(build_return_type(file_id, inner_pair)); } _ => unreachable!(), } @@ -150,29 +157,34 @@ fn build_function_type_use(function_pair: Pair) -> FunctionTypeUse { } } -fn build_generic_arguments(generic_arguments_pair: Pair) -> GenericArguments { +fn build_generic_arguments(file_id: usize, generic_arguments_pair: Pair) -> GenericArguments { let type_use_list_pair = generic_arguments_pair.into_inner().next().unwrap(); GenericArguments( type_use_list_pair .into_inner() - .map(|type_use_pair| expect_and_use(type_use_pair, Rule::TypeUse, build_type_use)) - .collect(), - ) -} - -fn build_generic_parameters(generic_parameters_pair: Pair) -> GenericParameters { - let identifier_list_pair = generic_parameters_pair.into_inner().next().unwrap(); - GenericParameters( - identifier_list_pair - .into_inner() - .map(|identifier_pair| { - expect_and_use(identifier_pair, Rule::Identifier, build_identifier) + .map(|type_use_pair| { + expect_and_use(file_id, type_use_pair, Rule::TypeUse, build_type_use) }) .collect(), ) } -fn build_tuple_arguments(tuple_arguments_pair: Pair) -> TupleArguments { +fn build_generic_parameters( + file_id: usize, + generic_parameters_pair: Pair, +) -> GenericParameters { + let identifier_list_pair = generic_parameters_pair.into_inner().next().unwrap(); + GenericParameters( + identifier_list_pair + .into_inner() + .map(|identifier_pair| { + expect_and_use(file_id, identifier_pair, Rule::Identifier, build_identifier) + }) + .collect(), + ) +} + +fn build_tuple_arguments(file_id: usize, tuple_arguments_pair: Pair) -> TupleArguments { let parentheses_optional_type_use_list_pair = tuple_arguments_pair.into_inner().next().unwrap(); let type_use_list_pair = parentheses_optional_type_use_list_pair .into_inner() @@ -182,20 +194,24 @@ fn build_tuple_arguments(tuple_arguments_pair: Pair) -> TupleArguments { TupleArguments( type_use_list_pair .into_inner() - .map(|type_use_pair| expect_and_use(type_use_pair, Rule::TypeUse, build_type_use)) + .map(|type_use_pair| { + expect_and_use(file_id, type_use_pair, Rule::TypeUse, build_type_use) + }) .collect(), ) } -fn build_implements_list(pair: Pair) -> ImplementsList { +fn build_implements_list(file_id: usize, pair: Pair) -> ImplementsList { ImplementsList( pair.into_inner() - .map(|type_use_pair| expect_and_use(type_use_pair, Rule::TypeUse, build_type_use)) + .map(|type_use_pair| { + expect_and_use(file_id, type_use_pair, Rule::TypeUse, build_type_use) + }) .collect(), ) } -fn build_function_type_modifier(pair: Pair) -> FunctionTypeModifier { +fn build_function_type_modifier(file_id: usize, pair: Pair) -> FunctionTypeModifier { let mut inner = pair.into_inner(); if inner.len() == 2 { FunctionTypeModifier::MutRef @@ -209,33 +225,52 @@ fn build_function_type_modifier(pair: Pair) -> FunctionTypeModifier { } } -fn build_parameters(parameters_pair: Pair) -> Parameters { +fn build_parameters(file_id: usize, parameters_pair: Pair) -> Parameters { Parameters( parameters_pair .into_inner() - .map(|parameter_pair| expect_and_use(parameter_pair, Rule::Parameter, build_parameter)) + .map(|parameter_pair| { + expect_and_use(file_id, parameter_pair, Rule::Parameter, build_parameter) + }) .collect(), ) } -fn build_parameter(parameter_pair: Pair) -> Parameter { +fn build_parameter(file_id: usize, parameter_pair: Pair) -> Parameter { let mut inner = parameter_pair.into_inner(); - let identifier = expect_and_use(inner.next().unwrap(), Rule::Identifier, build_identifier); - let type_use = expect_and_use(inner.next().unwrap(), Rule::TypeUse, build_type_use); + let identifier = expect_and_use( + file_id, + inner.next().unwrap(), + Rule::Identifier, + build_identifier, + ); + let type_use = expect_and_use( + file_id, + inner.next().unwrap(), + Rule::TypeUse, + build_type_use, + ); Parameter { identifier, type_use, } } -fn build_return_type(return_type_pair: Pair) -> ReturnType { +fn build_return_type(file_id: usize, return_type_pair: Pair) -> ReturnType { let mut inner = return_type_pair.into_inner(); - let declared_type = expect_and_use(inner.next().unwrap(), Rule::TypeUse, build_type_use); + let declared_type = expect_and_use( + file_id, + inner.next().unwrap(), + Rule::TypeUse, + build_type_use, + ); let references = inner .next() - .map(|ref_list_pair| expect_and_use(ref_list_pair, Rule::RefList, build_references)) + .map(|ref_list_pair| { + expect_and_use(file_id, ref_list_pair, Rule::RefList, build_references) + }) .unwrap_or_else(References::default); ReturnType { @@ -244,30 +279,30 @@ fn build_return_type(return_type_pair: Pair) -> ReturnType { } } -fn build_references(ref_list_pair: Pair) -> References { +fn build_references(file_id: usize, ref_list_pair: Pair) -> References { let mut inner = ref_list_pair.into_inner(); inner.next().unwrap(); // ref References( inner .map(|identifier_pair| { - expect_and_use(identifier_pair, Rule::Identifier, build_identifier) + expect_and_use(file_id, identifier_pair, Rule::Identifier, build_identifier) }) .collect(), ) } -fn build_compilation_unit(compilation_unit_pair: Pair) -> CompilationUnit { +fn build_compilation_unit(file_id: usize, compilation_unit_pair: Pair) -> CompilationUnit { let mut namespace = None; let mut declarations = vec![]; for inner_pair in compilation_unit_pair.into_inner() { match inner_pair.as_rule() { Rule::Namespace => { - namespace = Some(build_namespace(inner_pair)); + namespace = Some(build_namespace(file_id, inner_pair)); } Rule::ModuleLevelDeclaration => { - declarations.push(build_module_level_declaration(inner_pair)); + declarations.push(build_module_level_declaration(file_id, inner_pair)); } Rule::EOI => {} _ => unreachable!(), @@ -280,78 +315,99 @@ fn build_compilation_unit(compilation_unit_pair: Pair) -> CompilationUnit } } -fn build_namespace(namespace_pair: Pair) -> FullyQualifiedName { +fn build_namespace(file_id: usize, namespace_pair: Pair) -> FullyQualifiedName { let mut inner = namespace_pair.into_inner(); inner.next(); // ns - expect_and_use(inner.next().unwrap(), Rule::FullyQualifiedName, build_fqn) + expect_and_use( + file_id, + inner.next().unwrap(), + Rule::FullyQualifiedName, + build_fqn, + ) } -fn build_module_level_declaration(pair: Pair) -> ModuleLevelDeclaration { +fn build_module_level_declaration(file_id: usize, pair: Pair) -> ModuleLevelDeclaration { let inner_pair = pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::Module => ModuleLevelDeclaration::Module(build_module_declaration(inner_pair)), - Rule::Interface => { - ModuleLevelDeclaration::Interface(build_interface_declaration(inner_pair)) + Rule::Module => { + ModuleLevelDeclaration::Module(build_module_declaration(file_id, inner_pair)) } - Rule::Class => ModuleLevelDeclaration::Class(build_class_declaration(inner_pair)), + Rule::Interface => { + ModuleLevelDeclaration::Interface(build_interface_declaration(file_id, inner_pair)) + } + Rule::Class => ModuleLevelDeclaration::Class(build_class_declaration(file_id, inner_pair)), Rule::FunctionDefinition => { - ModuleLevelDeclaration::Function(build_function_definition(inner_pair)) + ModuleLevelDeclaration::Function(build_function_definition(file_id, inner_pair)) } Rule::PlatformFunction => ModuleLevelDeclaration::PlatformFunction( - build_platform_function_declaration(inner_pair), + build_platform_function_declaration(file_id, inner_pair), ), _ => unreachable!(), } } -fn build_interface_level_declaration(declaration_pair: Pair) -> InterfaceLevelDeclaration { +fn build_interface_level_declaration( + file_id: usize, + declaration_pair: Pair, +) -> InterfaceLevelDeclaration { let inner_pair = declaration_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::Module => InterfaceLevelDeclaration::Module(build_module_declaration(inner_pair)), + Rule::Module => { + InterfaceLevelDeclaration::Module(build_module_declaration(file_id, inner_pair)) + } Rule::Interface => { - InterfaceLevelDeclaration::Interface(build_interface_declaration(inner_pair)) + InterfaceLevelDeclaration::Interface(build_interface_declaration(file_id, inner_pair)) } - Rule::Class => InterfaceLevelDeclaration::Class(build_class_declaration(inner_pair)), - Rule::InterfaceFunction => { - InterfaceLevelDeclaration::Function(build_interface_function_declaration(inner_pair)) + Rule::Class => { + InterfaceLevelDeclaration::Class(build_class_declaration(file_id, inner_pair)) } + Rule::InterfaceFunction => InterfaceLevelDeclaration::Function( + build_interface_function_declaration(file_id, inner_pair), + ), Rule::InterfaceDefaultFunction => InterfaceLevelDeclaration::Function( - build_default_interface_function_declaration(inner_pair), + build_default_interface_function_declaration(file_id, inner_pair), ), Rule::InterfaceOperatorFunction => InterfaceLevelDeclaration::OperatorFunction( - build_interface_operator_function_declaration(inner_pair), + build_interface_operator_function_declaration(file_id, inner_pair), ), Rule::InterfaceDefaultOperatorFunction => InterfaceLevelDeclaration::OperatorFunction( - build_default_interface_operator_function_declaration(inner_pair), + build_default_interface_operator_function_declaration(file_id, inner_pair), ), _ => unreachable!(), } } -fn build_class_level_declaration(declaration_pair: Pair) -> ClassLevelDeclaration { +fn build_class_level_declaration( + file_id: usize, + declaration_pair: Pair, +) -> ClassLevelDeclaration { let inner_pair = declaration_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::Module => ClassLevelDeclaration::Module(build_module_declaration(inner_pair)), + Rule::Module => { + ClassLevelDeclaration::Module(build_module_declaration(file_id, inner_pair)) + } Rule::Interface => { - ClassLevelDeclaration::Interface(build_interface_declaration(inner_pair)) + ClassLevelDeclaration::Interface(build_interface_declaration(file_id, inner_pair)) } - Rule::Class => ClassLevelDeclaration::Class(build_class_declaration(inner_pair)), + Rule::Class => ClassLevelDeclaration::Class(build_class_declaration(file_id, inner_pair)), Rule::FunctionDefinition => { - ClassLevelDeclaration::Function(build_function_definition(inner_pair)) + ClassLevelDeclaration::Function(build_function_definition(file_id, inner_pair)) } - Rule::OperatorFunctionDefinition => { - ClassLevelDeclaration::OperatorFunction(build_operator_function_declaration(inner_pair)) + Rule::OperatorFunctionDefinition => ClassLevelDeclaration::OperatorFunction( + build_operator_function_declaration(file_id, inner_pair), + ), + Rule::PlatformFunction => ClassLevelDeclaration::PlatformFunction( + build_platform_function_declaration(file_id, inner_pair), + ), + Rule::Property => { + ClassLevelDeclaration::Property(build_property_declaration(file_id, inner_pair)) } - Rule::PlatformFunction => { - ClassLevelDeclaration::PlatformFunction(build_platform_function_declaration(inner_pair)) - } - Rule::Property => ClassLevelDeclaration::Property(build_property_declaration(inner_pair)), - Rule::Field => ClassLevelDeclaration::Field(build_field_declaration(inner_pair)), + Rule::Field => ClassLevelDeclaration::Field(build_field_declaration(file_id, inner_pair)), _ => unreachable!(), } } -fn build_module_declaration(module_pair: Pair) -> ModuleDeclaration { +fn build_module_declaration(file_id: usize, module_pair: Pair) -> ModuleDeclaration { let mut is_public = false; let mut identifier = None; let mut declarations = vec![]; @@ -363,10 +419,10 @@ fn build_module_declaration(module_pair: Pair) -> ModuleDeclaration { } Rule::Mod => {} Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::ModuleLevelDeclaration => { - declarations.push(build_module_level_declaration(inner_pair)); + declarations.push(build_module_level_declaration(file_id, inner_pair)); } _ => unreachable!(), } @@ -379,7 +435,7 @@ fn build_module_declaration(module_pair: Pair) -> ModuleDeclaration { } } -fn build_interface_declaration(interface_pair: Pair) -> InterfaceDeclaration { +fn build_interface_declaration(file_id: usize, interface_pair: Pair) -> InterfaceDeclaration { let mut is_public = false; let mut identifier = None; let mut generics = None; @@ -393,16 +449,16 @@ fn build_interface_declaration(interface_pair: Pair) -> InterfaceDeclarati } Rule::Int => {} Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::GenericParameters => { - generics = Some(build_generic_parameters(inner_pair)); + generics = Some(build_generic_parameters(file_id, inner_pair)); } Rule::ImplementsList => { - implements = Some(build_implements_list(inner_pair)); + implements = Some(build_implements_list(file_id, inner_pair)); } Rule::InterfaceLevelDeclaration => { - declarations.push(build_interface_level_declaration(inner_pair)); + declarations.push(build_interface_level_declaration(file_id, inner_pair)); } _ => unreachable!(), } @@ -417,7 +473,7 @@ fn build_interface_declaration(interface_pair: Pair) -> InterfaceDeclarati } } -fn build_class_declaration(class_pair: Pair) -> ClassDeclaration { +fn build_class_declaration(file_id: usize, class_pair: Pair) -> ClassDeclaration { let mut is_public = false; let mut identifier = None; let mut generics = None; @@ -432,19 +488,19 @@ fn build_class_declaration(class_pair: Pair) -> ClassDeclaration { } Rule::ClassKw => {} Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::GenericParameters => { - generics = Some(build_generic_parameters(inner_pair)); + generics = Some(build_generic_parameters(file_id, inner_pair)); } Rule::ClassConstructor => { - class_constructor = Some(build_class_constructor(inner_pair)); + class_constructor = Some(build_class_constructor(file_id, inner_pair)); } Rule::ImplementsList => { - implements = Some(build_implements_list(inner_pair)); + implements = Some(build_implements_list(file_id, inner_pair)); } Rule::ClassLevelDeclaration => { - declarations.push(build_class_level_declaration(inner_pair)); + declarations.push(build_class_level_declaration(file_id, inner_pair)); } _ => unreachable!(), } @@ -460,7 +516,10 @@ fn build_class_declaration(class_pair: Pair) -> ClassDeclaration { } } -fn build_function_definition(function_definition_pair: Pair) -> FunctionDefinition { +fn build_function_definition( + file_id: usize, + function_definition_pair: Pair, +) -> FunctionDefinition { let mut is_public = false; let mut modifier = None; let mut generics = None; @@ -475,23 +534,23 @@ fn build_function_definition(function_definition_pair: Pair) -> FunctionDe is_public = true; } Rule::FunctionModifier => { - modifier = Some(build_function_modifier(inner_pair)); + modifier = Some(build_function_modifier(file_id, inner_pair)); } Rule::Fn => {} Rule::GenericParameters => { - generics = Some(build_generic_parameters(inner_pair)); + generics = Some(build_generic_parameters(file_id, inner_pair)); } Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::Parameters => { - parameters = Some(build_parameters(inner_pair)); + parameters = Some(build_parameters(file_id, inner_pair)); } Rule::ReturnType => { - return_type = Some(build_return_type(inner_pair)); + return_type = Some(build_return_type(file_id, inner_pair)); } Rule::FunctionBody => { - body = Some(build_function_body(inner_pair)); + body = Some(build_function_body(file_id, inner_pair)); } _ => unreachable!(), } @@ -509,50 +568,58 @@ fn build_function_definition(function_definition_pair: Pair) -> FunctionDe } fn build_operator_function_declaration( + file_id: usize, operator_function_pair: Pair, ) -> OperatorFunctionDefinition { todo!() } fn build_platform_function_declaration( + file_id: usize, platform_function_pair: Pair, ) -> PlatformFunctionDeclaration { todo!() } fn build_interface_function_declaration( + file_id: usize, interface_function_pair: Pair, ) -> InterfaceFunctionDeclaration { todo!() } fn build_interface_operator_function_declaration( + file_id: usize, interface_operator_pair: Pair, ) -> InterfaceOperatorFunctionDeclaration { todo!() } fn build_default_interface_function_declaration( + file_id: usize, default_interface_function_pair: Pair, ) -> InterfaceFunctionDeclaration { todo!() } fn build_default_interface_operator_function_declaration( + file_id: usize, default_interface_operator_pair: Pair, ) -> InterfaceOperatorFunctionDeclaration { todo!() } -fn build_class_constructor(class_constructor_pair: Pair) -> ClassConstructor { +fn build_class_constructor(file_id: usize, class_constructor_pair: Pair) -> ClassConstructor { ClassConstructor( class_constructor_pair .into_inner() .map(|data_member_pair| { let inner_pair = data_member_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::Property => build_property_class_constructor_parameter(inner_pair), - Rule::Field => build_field_class_constructor_parameter(inner_pair), + Rule::Property => { + build_property_class_constructor_parameter(file_id, inner_pair) + } + Rule::Field => build_field_class_constructor_parameter(file_id, inner_pair), _ => unreachable!(), } }) @@ -560,7 +627,7 @@ fn build_class_constructor(class_constructor_pair: Pair) -> ClassConstruct ) } -fn build_function_modifier(modifier_pair: Pair) -> FunctionModifier { +fn build_function_modifier(file_id: usize, modifier_pair: Pair) -> FunctionModifier { let mut inner = modifier_pair.into_inner(); if inner.len() == 2 { FunctionModifier::MutRef @@ -575,19 +642,21 @@ fn build_function_modifier(modifier_pair: Pair) -> FunctionModifier { } } -fn build_function_body(body_pair: Pair) -> FunctionBody { +fn build_function_body(file_id: usize, body_pair: Pair) -> FunctionBody { let inner_pair = body_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { Rule::FunctionEqualsBody => FunctionBody::Equals(expect_and_use( + file_id, inner_pair.into_inner().next().unwrap(), Rule::Expression, build_expression, )), - Rule::BlockStatement => FunctionBody::Block(build_block_statement(inner_pair)), + Rule::BlockStatement => FunctionBody::Block(build_block_statement(file_id, inner_pair)), Rule::FunctionAliasBody => { let mut alias_body_pairs = inner_pair.into_inner(); alias_body_pairs.next().unwrap(); // Alias FunctionBody::Alias(expect_and_use( + file_id, alias_body_pairs.next().unwrap(), Rule::Identifier, build_identifier, @@ -598,16 +667,23 @@ fn build_function_body(body_pair: Pair) -> FunctionBody { } fn build_property_class_constructor_parameter( + file_id: usize, property_pair: Pair, ) -> ClassConstructorParameter { - ClassConstructorParameter::Property(build_property_declaration(property_pair)) + ClassConstructorParameter::Property(build_property_declaration(file_id, property_pair)) } -fn build_field_class_constructor_parameter(field_pair: Pair) -> ClassConstructorParameter { - ClassConstructorParameter::Field(build_field_declaration(field_pair)) +fn build_field_class_constructor_parameter( + file_id: usize, + field_pair: Pair, +) -> ClassConstructorParameter { + ClassConstructorParameter::Field(build_field_declaration(file_id, field_pair)) } -fn build_property_declaration(property_declaration_pair: Pair) -> PropertyDeclaration { +fn build_property_declaration( + file_id: usize, + property_declaration_pair: Pair, +) -> PropertyDeclaration { let mut is_mutable = false; let mut identifier = None; let mut declared_type = None; @@ -618,10 +694,10 @@ fn build_property_declaration(property_declaration_pair: Pair) -> Property is_mutable = true; } Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::TypeUse => { - declared_type = Some(build_type_use(inner_pair)); + declared_type = Some(build_type_use(file_id, inner_pair)); } _ => unreachable!(), } @@ -634,7 +710,7 @@ fn build_property_declaration(property_declaration_pair: Pair) -> Property } } -fn build_field_declaration(field_pair: Pair) -> FieldDeclaration { +fn build_field_declaration(file_id: usize, field_pair: Pair) -> FieldDeclaration { let mut is_mutable = false; let mut identifier = None; let mut declared_type = None; @@ -646,10 +722,10 @@ fn build_field_declaration(field_pair: Pair) -> FieldDeclaration { } Rule::Fld => {} Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::TypeUse => { - declared_type = Some(build_type_use(inner_pair)); + declared_type = Some(build_type_use(file_id, inner_pair)); } _ => unreachable!(), } @@ -662,17 +738,17 @@ fn build_field_declaration(field_pair: Pair) -> FieldDeclaration { } } -fn build_block_statement(block_statement_pair: Pair) -> BlockStatement { +fn build_block_statement(file_id: usize, block_statement_pair: Pair) -> BlockStatement { let mut statements = vec![]; let mut expression = None; for inner_pair in block_statement_pair.into_inner() { match inner_pair.as_rule() { Rule::Statement => { - statements.push(build_statement(inner_pair)); + statements.push(build_statement(file_id, inner_pair)); } Rule::Expression => { - expression = Some(build_expression(inner_pair)); + expression = Some(build_expression(file_id, inner_pair)); } _ => unreachable!(), } @@ -684,25 +760,30 @@ fn build_block_statement(block_statement_pair: Pair) -> BlockStatement { } } -fn build_statement(statement_pair: Pair) -> Statement { +fn build_statement(file_id: usize, statement_pair: Pair) -> Statement { let first = statement_pair.into_inner().next().unwrap(); match first.as_rule() { - Rule::BlockStatement => Statement::BlockStatement(build_block_statement(first)), + Rule::BlockStatement => Statement::BlockStatement(build_block_statement(file_id, first)), Rule::VariableDeclaration => { - Statement::VariableDeclarationStatement(build_variable_declaration(first)) + Statement::VariableDeclarationStatement(build_variable_declaration(file_id, first)) } - Rule::AssignmentStatement => Statement::AssignStatement(build_assignment_statement(first)), - Rule::CallStatement => Statement::CallStatement(build_call_statement(first)), - Rule::ReturnStatement => Statement::ReturnStatement(build_return_statement(first)), - Rule::IfStatement => Statement::IfStatement(build_if_statement(first)), - Rule::IfElseStatement => Statement::IfElseStatement(build_if_else_statement(first)), - Rule::WhileStatement => Statement::WhileStatement(build_while_statement(first)), - Rule::ForStatement => Statement::ForStatement(build_for_statement(first)), + Rule::AssignmentStatement => { + Statement::AssignStatement(build_assignment_statement(file_id, first)) + } + Rule::CallStatement => Statement::CallStatement(build_call_statement(file_id, first)), + Rule::ReturnStatement => Statement::ReturnStatement(build_return_statement(file_id, first)), + Rule::IfStatement => Statement::IfStatement(build_if_statement(file_id, first)), + Rule::IfElseStatement => { + Statement::IfElseStatement(build_if_else_statement(file_id, first)) + } + Rule::WhileStatement => Statement::WhileStatement(build_while_statement(file_id, first)), + Rule::ForStatement => Statement::ForStatement(build_for_statement(file_id, first)), _ => unreachable!(), } } fn build_variable_declaration( + file_id: usize, variable_declaration_pair: Pair, ) -> VariableDeclarationStatement { let mut is_mutable = false; @@ -717,13 +798,13 @@ fn build_variable_declaration( is_mutable = true; } Rule::Identifier => { - identifier = Some(build_identifier(inner_pair)); + identifier = Some(build_identifier(file_id, inner_pair)); } Rule::TypeUse => { - declared_type = Some(build_type_use(inner_pair)); + declared_type = Some(build_type_use(file_id, inner_pair)); } Rule::Expression => { - initializer = Some(build_expression(inner_pair)); + initializer = Some(build_expression(file_id, inner_pair)); } _ => unreachable!(), } @@ -737,16 +818,17 @@ fn build_variable_declaration( } } -fn build_assignment_statement(assignment_pair: Pair) -> AssignStatement { +fn build_assignment_statement(file_id: usize, assignment_pair: Pair) -> AssignStatement { let mut inner = assignment_pair.into_inner(); - let lhs = build_expression(inner.next().unwrap()); - let rhs = build_expression(inner.next().unwrap()); + let lhs = build_expression(file_id, inner.next().unwrap()); + let rhs = build_expression(file_id, inner.next().unwrap()); AssignStatement { lhs, rhs } } -fn build_call_statement(call_statement_pair: Pair) -> CallStatement { +fn build_call_statement(file_id: usize, call_statement_pair: Pair) -> CallStatement { let mut inner = call_statement_pair.into_inner(); let mut result = expect_and_use( + file_id, inner.next().unwrap(), Rule::PrimaryExpression, build_primary_expression, @@ -755,10 +837,10 @@ fn build_call_statement(call_statement_pair: Pair) -> CallStatement { while let Some(inner_pair) = inner.next() { match inner_pair.as_rule() { Rule::ObjectAccess => { - result = Expression::ObjectAccess(build_object_access(result, inner_pair)); + result = Expression::ObjectAccess(build_object_access(file_id, result, inner_pair)); } Rule::ParenthesesCall => { - result = Expression::Call(build_call_expression(result, inner_pair)); + result = Expression::Call(build_call_expression(file_id, result, inner_pair)); } Rule::PlusPlus => { result = Expression::UnarySuffix(SuffixExpression { @@ -779,46 +861,56 @@ fn build_call_statement(call_statement_pair: Pair) -> CallStatement { CallStatement(result) } -fn build_return_statement(return_statement_pair: Pair) -> ReturnStatement { +fn build_return_statement(file_id: usize, return_statement_pair: Pair) -> ReturnStatement { todo!() } -fn build_if_statement(if_statement_pair: Pair) -> IfStatement { +fn build_if_statement(file_id: usize, if_statement_pair: Pair) -> IfStatement { todo!() } -fn build_if_else_statement(if_else_statement_pair: Pair) -> IfElseStatement { +fn build_if_else_statement(file_id: usize, if_else_statement_pair: Pair) -> IfElseStatement { todo!() } -fn build_while_statement(while_statement_pair: Pair) -> WhileStatement { +fn build_while_statement(file_id: usize, while_statement_pair: Pair) -> WhileStatement { todo!() } -fn build_for_statement(for_statement_pair: Pair) -> ForStatement { +fn build_for_statement(file_id: usize, for_statement_pair: Pair) -> ForStatement { todo!() } -fn build_expression(expression_pair: Pair) -> Expression { +fn build_expression(file_id: usize, expression_pair: Pair) -> Expression { expect_and_use( + file_id, expression_pair.into_inner().next().unwrap(), Rule::TernaryExpression, build_ternary_expression, ) } -fn build_ternary_expression(ternary_pair: Pair) -> Expression { +fn build_ternary_expression(file_id: usize, ternary_pair: Pair) -> Expression { let mut inner = ternary_pair.into_inner(); if inner.len() == 3 { let condition = expect_and_use( + file_id, inner.next().unwrap(), Rule::OrExpression, build_or_expression, ); - let true_expression = - expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); - let false_expression = - expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); + let true_expression = expect_and_use( + file_id, + inner.next().unwrap(), + Rule::Expression, + build_expression, + ); + let false_expression = expect_and_use( + file_id, + inner.next().unwrap(), + Rule::Expression, + build_expression, + ); Expression::Ternary(TernaryExpression { condition: Box::new(condition), true_expression: Box::new(true_expression), @@ -826,6 +918,7 @@ fn build_ternary_expression(ternary_pair: Pair) -> Expression { }) } else { expect_and_use( + file_id, inner.next().unwrap(), Rule::OrExpression, build_or_expression, @@ -834,12 +927,12 @@ fn build_ternary_expression(ternary_pair: Pair) -> Expression { } macro_rules! build_binary_expression { - ( $pair:ident, $left_rule:expr, $left_fn:expr, $( $pat:pat => $arm:expr ),* $(,)? ) => {{ + ( $file_id:expr, $pair:ident, $left_rule:expr, $left_fn:expr, $( $pat:pat => $arm:expr ),* $(,)? ) => {{ let mut inner: Pairs = $pair.into_inner(); if inner.len() == 3 { - let left = expect_and_use(inner.next().unwrap(), $left_rule, $left_fn); + let left = expect_and_use($file_id, inner.next().unwrap(), $left_rule, $left_fn); let op = inner.next().unwrap(); // op - let right = expect_and_use(inner.next().unwrap(), Rule::Expression, build_expression); + let right = expect_and_use($file_id, inner.next().unwrap(), Rule::Expression, build_expression); Expression::Binary(BinaryExpression { left: Box::new(left), operator: match op.as_rule() { @@ -849,13 +942,14 @@ macro_rules! build_binary_expression { right: Box::new(right), }) } else { - expect_and_use(inner.next().unwrap(), $left_rule, $left_fn) + expect_and_use($file_id, inner.next().unwrap(), $left_rule, $left_fn) } }}; } -fn build_or_expression(or_expression_pair: Pair) -> Expression { +fn build_or_expression(file_id: usize, or_expression_pair: Pair) -> Expression { build_binary_expression!( + file_id, or_expression_pair, Rule::AndExpression, build_and_expression, @@ -863,8 +957,8 @@ fn build_or_expression(or_expression_pair: Pair) -> Expression { ) } -fn build_and_expression(and_expression_pair: Pair) -> Expression { - build_binary_expression!( +fn build_and_expression(file_id: usize, and_expression_pair: Pair) -> Expression { + build_binary_expression!(file_id, and_expression_pair, Rule::ComparisonExpression, build_comparison_expression, @@ -872,8 +966,11 @@ fn build_and_expression(and_expression_pair: Pair) -> Expression { ) } -fn build_comparison_expression(comparison_expression_pair: Pair) -> Expression { - build_binary_expression!( +fn build_comparison_expression( + file_id: usize, + comparison_expression_pair: Pair, +) -> Expression { + build_binary_expression!(file_id, comparison_expression_pair, Rule::ShiftExpression, build_shift_expression, @@ -886,8 +983,8 @@ fn build_comparison_expression(comparison_expression_pair: Pair) -> Expres ) } -fn build_shift_expression(shift_expression_pair: Pair) -> Expression { - build_binary_expression!( +fn build_shift_expression(file_id: usize, shift_expression_pair: Pair) -> Expression { + build_binary_expression!(file_id, shift_expression_pair, Rule::AdditiveExpression, build_additive_expression, @@ -896,8 +993,8 @@ fn build_shift_expression(shift_expression_pair: Pair) -> Expression { ) } -fn build_additive_expression(add_expression_pair: Pair) -> Expression { - build_binary_expression!( +fn build_additive_expression(file_id: usize, add_expression_pair: Pair) -> Expression { + build_binary_expression!(file_id, add_expression_pair, Rule::MultiplicativeExpression, build_multiplicative_expression, @@ -906,8 +1003,11 @@ fn build_additive_expression(add_expression_pair: Pair) -> Expression { ) } -fn build_multiplicative_expression(multiplicative_expression_pair: Pair) -> Expression { - build_binary_expression!( +fn build_multiplicative_expression( + file_id: usize, + multiplicative_expression_pair: Pair, +) -> Expression { + build_binary_expression!(file_id, multiplicative_expression_pair, Rule::PrefixExpression, build_prefix_expression, @@ -916,9 +1016,10 @@ fn build_multiplicative_expression(multiplicative_expression_pair: Pair) - ) } -fn build_prefix_expression(prefix_pair: Pair) -> Expression { +fn build_prefix_expression(file_id: usize, prefix_pair: Pair) -> Expression { let mut inner_rev = prefix_pair.into_inner().rev(); let mut result = expect_and_use( + file_id, inner_rev.next().unwrap(), Rule::SuffixExpression, build_suffix_expression, @@ -967,9 +1068,10 @@ fn build_prefix_expression(prefix_pair: Pair) -> Expression { result } -fn build_suffix_expression(suffix_pair: Pair) -> Expression { +fn build_suffix_expression(file_id: usize, suffix_pair: Pair) -> Expression { let mut inner = suffix_pair.into_inner(); let mut result = expect_and_use( + file_id, inner.next().unwrap(), Rule::PrimaryExpression, build_primary_expression, @@ -977,10 +1079,10 @@ fn build_suffix_expression(suffix_pair: Pair) -> Expression { while let Some(suffix_pair) = inner.next() { match suffix_pair.as_rule() { Rule::ObjectAccess => { - result = Expression::ObjectAccess(build_object_access(result, suffix_pair)) + result = Expression::ObjectAccess(build_object_access(file_id, result, suffix_pair)) } Rule::ParenthesesCall => { - result = Expression::Call(build_call_expression(result, suffix_pair)) + result = Expression::Call(build_call_expression(file_id, result, suffix_pair)) } Rule::PlusPlus => { result = Expression::UnarySuffix(SuffixExpression { @@ -1000,18 +1102,23 @@ fn build_suffix_expression(suffix_pair: Pair) -> Expression { result } -fn build_call_expression(callee: Expression, parentheses_call_pair: Pair) -> CallExpression { +fn build_call_expression( + file_id: usize, + callee: Expression, + parentheses_call_pair: Pair, +) -> CallExpression { let mut turbo_fish = None; let mut arguments = vec![]; for inner_pair in parentheses_call_pair.into_inner() { match inner_pair.as_rule() { Rule::TurboFish => { - turbo_fish = Some(build_turbo_fish(inner_pair)); + turbo_fish = Some(build_turbo_fish(file_id, inner_pair)); } Rule::ExpressionList => { for expression_pair in inner_pair.into_inner() { arguments.push(expect_and_use( + file_id, expression_pair, Rule::Expression, build_expression, @@ -1019,7 +1126,7 @@ fn build_call_expression(callee: Expression, parentheses_call_pair: Pair) } } Rule::Closure => { - arguments.push(Expression::Closure(build_closure(inner_pair))); + arguments.push(Expression::Closure(build_closure(file_id, inner_pair))); } _ => unreachable!(), } @@ -1037,27 +1144,37 @@ fn build_call_expression(callee: Expression, parentheses_call_pair: Pair) } } -fn build_turbo_fish(turbo_fish_pair: Pair) -> TurboFish { +fn build_turbo_fish(file_id: usize, turbo_fish_pair: Pair) -> TurboFish { TurboFish(build_generic_arguments( + file_id, turbo_fish_pair.into_inner().next().unwrap(), )) } -fn build_primary_expression(primary_expression_pair: Pair) -> Expression { +fn build_primary_expression(file_id: usize, primary_expression_pair: Pair) -> Expression { let first_pair = primary_expression_pair.into_inner().next().unwrap(); match first_pair.as_rule() { - Rule::Literal => Expression::Literal(build_literal(first_pair)), - Rule::FullyQualifiedName => Expression::FullyQualifiedName(build_fqn(first_pair)), - Rule::Closure => Expression::Closure(build_closure(first_pair)), + Rule::Literal => Expression::Literal(build_literal(file_id, first_pair)), + Rule::FullyQualifiedName => Expression::FullyQualifiedName(build_fqn(file_id, first_pair)), + Rule::Closure => Expression::Closure(build_closure(file_id, first_pair)), Rule::ParenthesizedExpression => { let inner_expression = first_pair.into_inner().next().unwrap(); - expect_and_use(inner_expression, Rule::Expression, build_expression) + expect_and_use( + file_id, + inner_expression, + Rule::Expression, + build_expression, + ) } _ => unreachable!(), } } -fn build_object_access(receiver: Expression, navigations_pair: Pair) -> ObjectAccess { +fn build_object_access( + file_id: usize, + receiver: Expression, + navigations_pair: Pair, +) -> ObjectAccess { ObjectAccess { receiver: Box::new(receiver), navigations: ObjectNavigations( @@ -1065,6 +1182,7 @@ fn build_object_access(receiver: Expression, navigations_pair: Pair) -> Ob .into_inner() .map(|identifier_pair| { ObjectNavigation::Identifier(Box::new(expect_and_use( + file_id, identifier_pair, Rule::Identifier, build_identifier, @@ -1075,35 +1193,35 @@ fn build_object_access(receiver: Expression, navigations_pair: Pair) -> Ob } } -fn build_closure(closure_pair: Pair) -> Closure { +fn build_closure(file_id: usize, closure_pair: Pair) -> Closure { todo!() } -fn build_literal(literal_pair: Pair) -> Literal { +fn build_literal(file_id: usize, literal_pair: Pair) -> Literal { let inner_pair = literal_pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::NumberLiteral => build_number_literal(inner_pair), - Rule::StringLiteral => build_string_literal(inner_pair), - Rule::BooleanLiteral => build_boolean_literal(inner_pair), + Rule::NumberLiteral => build_number_literal(file_id, inner_pair), + Rule::StringLiteral => build_string_literal(file_id, inner_pair), + Rule::BooleanLiteral => build_boolean_literal(file_id, inner_pair), _ => unreachable!(), } } -fn build_number_literal(pair: Pair) -> Literal { +fn build_number_literal(file_id: usize, pair: Pair) -> Literal { todo!() } -fn build_string_literal(pair: Pair) -> Literal { +fn build_string_literal(file_id: usize, pair: Pair) -> Literal { let inner_pair = pair.into_inner().next().unwrap(); match inner_pair.as_rule() { - Rule::SingleQuoteString => build_single_quote_string(inner_pair), - Rule::DoubleQuoteString => build_double_quote_string(inner_pair), - Rule::BacktickString => build_backtick_string(inner_pair), + Rule::SingleQuoteString => build_single_quote_string(file_id, inner_pair), + Rule::DoubleQuoteString => build_double_quote_string(file_id, inner_pair), + Rule::BacktickString => build_backtick_string(file_id, inner_pair), _ => unreachable!(), } } -fn build_boolean_literal(pair: Pair) -> Literal { +fn build_boolean_literal(file_id: usize, pair: Pair) -> Literal { let inner_pair = pair.into_inner().next().unwrap(); match inner_pair.as_rule() { Rule::True => Literal::Boolean(true), @@ -1112,15 +1230,15 @@ fn build_boolean_literal(pair: Pair) -> Literal { } } -fn build_single_quote_string(pair: Pair) -> Literal { +fn build_single_quote_string(file_id: usize, pair: Pair) -> Literal { let inner_pair = pair.into_inner().next().unwrap(); Literal::String(inner_pair.as_span().as_str().to_string()) } -fn build_double_quote_string(pair: Pair) -> Literal { +fn build_double_quote_string(file_id: usize, pair: Pair) -> Literal { todo!() } -fn build_backtick_string(pair: Pair) -> Literal { +fn build_backtick_string(file_id: usize, pair: Pair) -> Literal { todo!() } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e418616..8561e90 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -55,15 +55,17 @@ pub enum SuffixUnaryOperator { #[derive(Debug, Clone)] pub struct Identifier { pub name: String, + pub file_id: usize, pub range: Range, scope_id: Option, symbol: Option, } impl Identifier { - pub fn new(name: &str, range: Range) -> Self { + pub fn new(name: &str, file_id: usize, range: Range) -> Self { Identifier { name: name.to_string(), + file_id, range, scope_id: None, symbol: None, @@ -90,16 +92,18 @@ impl Identifier { #[derive(Debug)] pub struct FullyQualifiedName { pub identifiers: Vec, + pub file_id: usize, pub range: Range, scope_id: Option, symbol: Option, } impl FullyQualifiedName { - pub fn new(identifiers: Vec, range: Range) -> Self { + pub fn new(identifiers: Vec, file_id: usize, range: Range) -> Self { FullyQualifiedName { identifiers, range, + file_id, scope_id: None, symbol: None, } diff --git a/src/bin/dmc/name_analysis.rs b/src/bin/dmc/name_analysis.rs index ae524f3..db046e9 100644 --- a/src/bin/dmc/name_analysis.rs +++ b/src/bin/dmc/name_analysis.rs @@ -17,7 +17,7 @@ pub fn name_analysis(path: &Path) -> Result<(), Box> { match parse_result { Ok(mut pairs) => { let compilation_unit_pair = pairs.next().unwrap(); - let mut compilation_unit = build_ast(compilation_unit_pair); + let mut compilation_unit = build_ast(file_id, compilation_unit_pair); let mut symbol_table = SymbolTable::new(); let diagnostics = analyze_names(file_id, &mut compilation_unit, &mut symbol_table); if diagnostics.is_empty() { diff --git a/src/bin/dmc/p3.rs b/src/bin/dmc/p3.rs index 3710d91..36bd28a 100644 --- a/src/bin/dmc/p3.rs +++ b/src/bin/dmc/p3.rs @@ -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(compilation_unit_pair); + let compilation_unit = build_ast(0, compilation_unit_pair); let mut indent_writer = IndentWriter::new(0, " ", Box::new(std::io::stdout())); compilation_unit .pretty_print(&mut indent_writer) diff --git a/src/bin/dmc/unparse.rs b/src/bin/dmc/unparse.rs index a902b04..ec2851d 100644 --- a/src/bin/dmc/unparse.rs +++ b/src/bin/dmc/unparse.rs @@ -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(compilation_unit_pair); + let compilation_unit = build_ast(0, compilation_unit_pair); let mut writer = IndentWriter::new(0, " ", Box::new(std::io::stdout())); compilation_unit .unparse(&mut writer) diff --git a/src/name_analysis/gather.rs b/src/name_analysis/gather.rs index f666541..a455dba 100644 --- a/src/name_analysis/gather.rs +++ b/src/name_analysis/gather.rs @@ -1,10 +1,45 @@ use crate::ast::named::Named; use crate::ast::*; use crate::name_analysis::fqn_context::FqnContext; -use crate::name_analysis::symbol::{FunctionSymbol, Symbol, VariableSymbol}; -use crate::name_analysis::symbol_table::SymbolTable; +use crate::name_analysis::symbol::{FunctionSymbol, ModuleSymbol, SourceDefinition, Symbol, VariableSymbol}; +use crate::name_analysis::symbol_table::{SymbolInsertError, SymbolTable}; use crate::name_analysis::DiagnosticsContainer; use codespan_reporting::diagnostic::{Diagnostic, Label}; +use std::range::Range; + +fn handle_insert_error( + err: SymbolInsertError, + error_symbol_name: &str, + error_file_id: usize, + error_range: Range, + symbol_types: &str, + diagnostics: &mut DiagnosticsContainer, +) { + match err { + SymbolInsertError::SymbolAlreadyDefined(s) => { + let already_defined_definition = s.definition(); + + diagnostics.add( + Diagnostic::error() + .with_message(format!( + "{} symbol '{}' already defined in the current scope.", + symbol_types, error_symbol_name, + )) + .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."), + ), + ); + } + } +} pub(super) fn gather_module_level_declaration( declaration: &mut ModuleLevelDeclaration, @@ -14,6 +49,9 @@ pub(super) fn gather_module_level_declaration( ) { use ModuleLevelDeclaration::*; match declaration { + Module(module_declaration) => { + gather_module_declaration(module_declaration, symbol_table, fqn_context, diagnostics); + } Function(function_definition) => { gather_function_definition(function_definition, symbol_table, fqn_context, diagnostics) } @@ -21,28 +59,78 @@ pub(super) fn gather_module_level_declaration( } } +fn gather_module_declaration( + declaration: &mut ModuleDeclaration, + symbol_table: &mut SymbolTable, + fqn_context: &mut FqnContext, + diagnostics: &mut DiagnosticsContainer, +) { + // 1. Add mod identifier symbol + // 2. Update fqn context + // 3. Push scope + // 4. Process declarations + // 5. Pop scope + + let module_name = declaration.identifier.name(); + + let insert_result = symbol_table.insert( + &module_name, + Symbol::Module(ModuleSymbol::new( + &fqn_context.resolve(&module_name), + &module_name, + declaration.is_public, + &declaration.identifier, + )), + ); + + if let Err(err) = insert_result { + handle_insert_error( + err, + &module_name, + declaration.identifier.file_id, + declaration.identifier.range, + "module/type", + diagnostics, + ) + } + + fqn_context.push(module_name.to_string()); + + symbol_table.push_scope(&format!("Module '{}' Scope", 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_function_definition( function: &mut FunctionDefinition, symbol_table: &mut SymbolTable, fqn_context: &mut FqnContext, diagnostics: &mut DiagnosticsContainer, ) { - let declared_name = function.identifier.name().to_string(); + let declared_name = function.identifier.name(); let resolved_name = fqn_context.resolve(&declared_name); let insert_result = symbol_table.insert( - declared_name.clone(), - Symbol::Function(FunctionSymbol { - fqn: resolved_name.clone(), - declared_name, - is_public: function.is_public, - }), + &declared_name, + Symbol::Function(FunctionSymbol::new( + &resolved_name, + &declared_name, + function.is_public, + &function.identifier, + )), ); - if let Err(msg) = insert_result { - diagnostics.add(|file_id| { - Diagnostic::error().with_label(Label::primary(file_id, function.identifier.range)) - }); + if let Err(err) = insert_result { + handle_insert_error( + err, + &declared_name, + function.identifier.file_id, + function.identifier.range, + "function/variable", + diagnostics, + ) } function @@ -80,18 +168,28 @@ fn gather_parameter( let parameter_name = parameter.identifier.name(); let insert_result = symbol_table.insert( - parameter_name.to_string(), - Symbol::Variable(VariableSymbol { - name: parameter_name.to_string(), - is_mutable: false, - }), + ¶meter_name, + Symbol::Variable(VariableSymbol::new( + ¶meter_name, + false, + SourceDefinition::from_identifier(¶meter.identifier), + )), ); - - if let Err(msg) = insert_result { - diagnostics.add_error_at_identifier(&msg, ¶meter.identifier); + + if let Err(err) = insert_result { + handle_insert_error( + err, + ¶meter_name, + parameter.identifier.file_id, + parameter.identifier.range, + "function/variable", + diagnostics, + ) } - - parameter.identifier.set_scope_id(symbol_table.current_scope_id()); + + parameter + .identifier + .set_scope_id(symbol_table.current_scope_id()); } fn gather_function_body( @@ -114,7 +212,7 @@ fn gather_block_statement( diagnostics: &mut DiagnosticsContainer, ) { symbol_table.push_scope("BlockStatementScope"); - gather_block_statement(block, symbol_table, fqn_context, diagnostics); + gather_block_statement_inner(block, symbol_table, fqn_context, diagnostics); symbol_table.pop_scope(); } @@ -158,24 +256,32 @@ fn gather_variable_declaration( symbol_table: &mut SymbolTable, diagnostics: &mut DiagnosticsContainer, ) { - let variable_name = variable_declaration.identifier.name().to_string(); + let variable_name = variable_declaration.identifier.name(); let insert_result = symbol_table.insert( - variable_name.clone(), - Symbol::Variable(VariableSymbol { - name: variable_name, - is_mutable: variable_declaration.is_mutable, - }), + &variable_name, + Symbol::Variable(VariableSymbol::new( + &variable_name, + variable_declaration.is_mutable, + SourceDefinition::from_identifier(&variable_declaration.identifier), + )), ); - if let Err(msg) = insert_result { - diagnostics.add_error_at_identifier(&msg, &variable_declaration.identifier); + if let Err(err) = insert_result { + handle_insert_error( + err, + &variable_name, + variable_declaration.identifier.file_id, + variable_declaration.identifier.range, + "function/variable", + diagnostics, + ) } variable_declaration .identifier .set_scope_id(symbol_table.current_scope_id()); - + if let Some(initializer) = &mut variable_declaration.initializer { gather_expression(initializer, symbol_table, diagnostics); } diff --git a/src/name_analysis/mod.rs b/src/name_analysis/mod.rs index 3c3b8b1..663e00b 100644 --- a/src/name_analysis/mod.rs +++ b/src/name_analysis/mod.rs @@ -6,6 +6,7 @@ use crate::name_analysis::gather::gather_module_level_declaration; use crate::name_analysis::resolve::resolve_module_level_declaration; use crate::name_analysis::symbol_table::SymbolTable; use codespan_reporting::diagnostic::{Diagnostic, Label}; +use log::debug; mod fqn_context; mod gather; @@ -26,8 +27,8 @@ impl DiagnosticsContainer { } } - pub fn add(&mut self, f: impl FnOnce(usize) -> DmDiagnostic) { - self.diagnostics.push(f(self.file_id)); + pub fn add(&mut self, diagnostic: DmDiagnostic) { + self.diagnostics.push(diagnostic); } pub fn add_error_at_identifier(&mut self, msg: &str, identifier: &Identifier) { @@ -86,15 +87,16 @@ mod tests { use pest::Parser; fn assert_no_diagnostics(src: &str) { + let mut files = SimpleFiles::new(); + let test_file_id = files.add("test.dm", src); + let parse_result = DeimosParser::parse(Rule::CompilationUnit, src); if let Err(err) = &parse_result { panic!("{:?}", err); } - let compilation_unit_pair = parse_result.unwrap().next().unwrap(); - let mut ast = build_ast(compilation_unit_pair); - let mut files = SimpleFiles::new(); - let test_file_id = files.add("test.dm", src); + let compilation_unit_pair = parse_result.unwrap().next().unwrap(); + let mut ast = build_ast(test_file_id, compilation_unit_pair); let mut symbol_table = SymbolTable::new(); diff --git a/src/name_analysis/resolve.rs b/src/name_analysis/resolve.rs index 1925da4..fb5aab5 100644 --- a/src/name_analysis/resolve.rs +++ b/src/name_analysis/resolve.rs @@ -128,10 +128,16 @@ fn resolve_fully_qualified_name( Ok(symbol) => { fully_qualified_name.set_symbol(symbol.clone()); } - Err(e) => diagnostics.add(|file_id| { + Err(e) => diagnostics.add( Diagnostic::error() - .with_message(e) - .with_label(Label::primary(file_id, fully_qualified_name.range)) - }), + .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, + )), + ), } } diff --git a/src/name_analysis/symbol.rs b/src/name_analysis/symbol.rs index 14d1620..c1c7678 100644 --- a/src/name_analysis/symbol.rs +++ b/src/name_analysis/symbol.rs @@ -1,9 +1,35 @@ +use crate::ast::Identifier; use std::fmt::Display; +use std::range::Range; + +#[derive(Clone, Debug)] +pub struct SourceDefinition { + file_id: usize, + range: Range, +} + +impl SourceDefinition { + pub fn from_identifier(identifier: &Identifier) -> Self { + SourceDefinition { + file_id: identifier.file_id, + range: identifier.range, + } + } + + pub fn file_id(&self) -> usize { + self.file_id + } + + pub fn range(&self) -> Range { + self.range.clone() + } +} #[derive(Debug, Clone)] pub enum Symbol { Function(FunctionSymbol), Variable(VariableSymbol), + Module(ModuleSymbol), } impl Symbol { @@ -11,6 +37,15 @@ impl Symbol { 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(), + } + } + + pub fn definition(&self) -> &SourceDefinition { + match self { + Symbol::Function(s) => s.definition(), + Symbol::Module(s) => s.definition(), + Symbol::Variable(s) => s.definition(), } } } @@ -21,6 +56,7 @@ impl Display for Symbol { match self { Function(function_symbol) => write!(f, "{}", function_symbol), Variable(variable_symbol) => write!(f, "{}", variable_symbol), + Module(module_symbol) => write!(f, "{}", module_symbol), } } } @@ -30,6 +66,27 @@ pub struct FunctionSymbol { pub fqn: String, pub declared_name: String, pub is_public: bool, + definition: SourceDefinition, +} + +impl FunctionSymbol { + pub fn new( + fqn: &str, + declared_name: &str, + is_public: bool, + identifier: &Identifier, + ) -> FunctionSymbol { + FunctionSymbol { + fqn: fqn.to_string(), + declared_name: declared_name.to_string(), + is_public, + definition: SourceDefinition::from_identifier(identifier), + } + } + + fn definition(&self) -> &SourceDefinition { + &self.definition + } } impl Display for FunctionSymbol { @@ -46,6 +103,21 @@ impl Display for FunctionSymbol { pub struct VariableSymbol { pub name: String, pub is_mutable: bool, + definition: SourceDefinition, +} + +impl VariableSymbol { + pub fn new(name: &str, is_mutable: bool, definition: SourceDefinition) -> Self { + VariableSymbol { + name: name.to_string(), + is_mutable, + definition, + } + } + + pub fn definition(&self) -> &SourceDefinition { + &self.definition + } } impl Display for VariableSymbol { @@ -56,4 +128,42 @@ impl Display for VariableSymbol { self.name, self.is_mutable ) } -} \ No newline at end of file +} + +#[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 + ) + } +} diff --git a/src/name_analysis/symbol_table.rs b/src/name_analysis/symbol_table.rs index c280704..4941d3d 100644 --- a/src/name_analysis/symbol_table.rs +++ b/src/name_analysis/symbol_table.rs @@ -1,14 +1,35 @@ use crate::name_analysis::symbol::Symbol; use std::collections::HashMap; use std::fmt::Display; +use crate::name_analysis::symbol_table::SymbolInsertError::SymbolAlreadyDefined; +use crate::name_analysis::symbol_table::SymbolLookupError::NoDefinition; pub struct Scope { parent: Option, - symbols: HashMap, + function_and_variable_symbols: HashMap, + type_and_module_symbols: HashMap, debug_name: String, } -#[derive(Default)] +impl Scope { + pub fn new(parent: Option, debug_name: String) -> Scope { + Scope { + parent, + function_and_variable_symbols: HashMap::new(), + type_and_module_symbols: HashMap::new(), + debug_name, + } + } +} + +pub enum SymbolInsertError { + SymbolAlreadyDefined(Symbol), +} + +pub enum SymbolLookupError { + NoDefinition +} + pub struct SymbolTable { scopes: Vec, current_scope_id: usize, @@ -17,13 +38,10 @@ pub struct SymbolTable { /// Contains a vec of scopes, like a flattened tree impl SymbolTable { pub fn new() -> Self { - let mut t = SymbolTable::default(); - t.scopes.push(Scope { - parent: None, - symbols: HashMap::new(), - debug_name: String::from("Global Scope"), - }); - t.current_scope_id = 0; + let mut t = SymbolTable { + scopes: vec![Scope::new(None, String::from("GlobalScope"))], + current_scope_id: 0, + }; t } @@ -33,11 +51,8 @@ impl SymbolTable { pub fn push_scope(&mut self, debug_name: &str) { let id = self.scopes.len(); - self.scopes.push(Scope { - parent: Some(self.current_scope_id), - symbols: HashMap::new(), - debug_name: debug_name.to_string(), - }); + self.scopes + .push(Scope::new(Some(self.current_scope_id), debug_name.to_string())); self.current_scope_id = id; } @@ -47,24 +62,47 @@ 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 in current scope.", - current_symbol.name() - )) + 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) + { + Err(SymbolAlreadyDefined(defined_symbol.clone())) } else { self.scopes[self.current_scope_id] - .symbols - .insert(name, symbol); + .function_and_variable_symbols + .insert(name.to_string(), symbol); Ok(()) } } - pub fn lookup(&self, name: &str, scope_id: usize) -> Result<&Symbol, String> { + 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) + { + Err(SymbolAlreadyDefined(defined_symbol.clone())) + } else { + self.scopes[self.current_scope_id] + .type_and_module_symbols + .insert(name.to_string(), 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.symbols.get(name) { + if let Some(symbol) = scope.function_and_variable_symbols.get(name) { return Ok(symbol); } scope_opt = if let Some(parent_id) = scope.parent { @@ -73,15 +111,16 @@ impl SymbolTable { None }; } - Err(format!("Symbol '{}' not found in current scope.", name)) + Err(NoDefinition) } } impl Display for SymbolTable { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 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.symbols { + for (name, symbol) in &scope.function_and_variable_symbols { writeln!(f, " {}({})", name, symbol)?; } }