diff --git a/src/protocol/lexer.rs b/src/protocol/lexer.rs index 84e882204871f98f1b2b02ac456749e6b97a95e9..19b3a7e0b137460a9d2d9a1c21889569a5deb857 100644 --- a/src/protocol/lexer.rs +++ b/src/protocol/lexer.rs @@ -500,6 +500,9 @@ impl Lexer<'_> { backup_pos: &mut InputPosition ) -> Result<(), ParseError2> { // Consume identifier + if !ident.value.is_empty() { + ident.value.extend(b"::"); + } let ident_start = ident.value.len(); ident.value.extend(l.consume_ident()?); ident.parts.push(NamespacedIdentifierPart::Identifier{ @@ -510,7 +513,7 @@ impl Lexer<'_> { // Maybe consume polymorphic args. *backup_pos = l.source.pos(); l.consume_whitespace(false)?; - let had_poly_args = match l.consume_polymorphic_args(h, true)? { + match l.consume_polymorphic_args(h, true)? { Some(args) => { let poly_start = ident.poly_args.len(); ident.poly_args.extend(args); @@ -525,7 +528,7 @@ impl Lexer<'_> { None => {} }; - Ok(had_poly_args) + Ok(()) } let mut ident = NamespacedIdentifier2{ diff --git a/src/protocol/parser/utils.rs b/src/protocol/parser/utils.rs index f7bcc9d066cdc370fe97a75668528869400261c7..4122a16a636f5ec10a4c99f5a25a6d94b8153f51 100644 --- a/src/protocol/parser/utils.rs +++ b/src/protocol/parser/utils.rs @@ -1,4 +1,4 @@ -use crate::protocol::ast::*; + use crate::protocol::ast::*; use crate::protocol::inputsource::*; use super::symbol_table::*; use super::type_table::*; @@ -10,7 +10,7 @@ pub(crate) enum FindTypeResult<'t, 'i> { // Could not match symbol SymbolNotFound{ident_pos: InputPosition}, // Matched part of the namespaced identifier, but not completely - SymbolPartial{ident_pos: InputPosition, symbol_pos: InputPosition, ident_iter: NamespacedIdentifier2Iter<'i>}, + SymbolPartial{ident_pos: InputPosition, ident_iter: NamespacedIdentifier2Iter<'i>}, // Symbol matched, but points to a namespace/module instead of a type SymbolNamespace{ident_pos: InputPosition, symbol_pos: InputPosition}, } @@ -29,15 +29,12 @@ impl<'t, 'i> FindTypeResult<'t, 'i> { "Could not resolve this identifier to a symbol" )) }, - FindTypeResult::SymbolPartial{ident_pos, symbol_pos, ident_iter} => { + FindTypeResult::SymbolPartial{ident_pos, ident_iter} => { Err(ParseError2::new_error( module_source, ident_pos, - "Could not fully resolve this identifier to a symbol" - ).with_postfixed_info( - module_source, symbol_pos, &format!( - "The partial identifier '{}' was matched to this symbol", - String::from_utf8_lossy(ident_iter.returned_section()), + "Could not fully resolve this identifier to a symbol, was only able to match '{}'", + &String::from_utf8_lossy(ident_iter.returned_section()) ) )) }, @@ -71,8 +68,7 @@ pub(crate) fn find_type_definition<'t, 'i>( let symbol = symbol.unwrap(); if ident_iter.num_remaining() != 0 { return FindTypeResult::SymbolPartial{ - ident_pos: identifier.position, - symbol_pos: symbol.position, + ident_pos: identifier.position, ident_iter }; } diff --git a/src/protocol/tests/parser_imports.rs b/src/protocol/tests/parser_imports.rs index 94faacc68bcf7b037fc2a7f884c56664994b31bf..bbcbe96e11f2c0dc989c38b046713f13fb0d8be2 100644 --- a/src/protocol/tests/parser_imports.rs +++ b/src/protocol/tests/parser_imports.rs @@ -147,6 +147,103 @@ fn test_multi_symbol_import() { // .expect_ok(); } +#[test] +fn test_illegal_import_use() { + Tester::new("unexpected polymorphic args") + .with_source(" + #module external + struct Foo { byte f } + ") + .with_source(" + import external; + byte caller() { + auto foo = external::Foo{ f: 0 }; + return foo.f; + } + ") + .compile() + .expect_err() + .error(|e| { e + .assert_msg_has(0, "the type Foo is not polymorphic"); + }); + + Tester::new("mismatched polymorphic args") + .with_source(" + #module external + struct Foo{ T f } + ") + .with_source(" + import external; + byte caller() { + auto foo = external::Foo{ f: 0 }; + return foo.f; + }") + .compile() + .expect_err() + .error(|e| { e + .assert_msg_has(0, "expected 1 polymorphic") + .assert_msg_has(0, "2 were specified"); + }); + + Tester::new("module as type") + .with_source(" + #module external + ") + .with_source(" + import external; + byte caller() { + auto foo = external{ f: 0 }; + return 0; + } + ") + .compile() + .expect_err() + .error(|e| { e + .assert_msg_has(0, "resolved to a namespace"); + }); + + Tester::new("more namespaces than needed, not polymorphic") + .with_source(" + #module external + struct Foo { byte f } + ") + .with_source(" + import external; + byte caller() { + auto foo = external::Foo::f{ f: 0 }; + return 0; + }") + .compile() + .expect_err() + .error(|e| { e + .assert_msg_has(0, "not fully resolve this identifier") + .assert_msg_has(0, "able to match 'external::Foo'"); + }); + + Tester::new("import from another import") + .with_source(" + #module mod1 + struct Foo { byte f } + ") + .with_source(" + #module mod2 + import mod1::Foo; + struct Bar { Foo f } + ") + .with_source(" + import mod2; + byte caller() { + auto bar = mod2::Bar{ f: mod2::Foo{ f: 0 } }; + return var.f.f; + }") + .compile() + .expect_err() + .error(|e| { e + .assert_msg_has(0, "Could not resolve this identifier") + .assert_occurs_at(0, "mod2::Foo"); + }); +} + // TODO: Test incorrect imports: // 1. importing a module // 2. import something a module imports