Skip to content

Commit 7851cb2

Browse files
committed
jule: update module behavior and and import paths
1 parent 3ab8591 commit 7851cb2

File tree

2 files changed

+75
-51
lines changed

2 files changed

+75
-51
lines changed

std/jule/sema/api.jule

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ const (
1414
)
1515

1616
// Builds symbol table of AST.
17-
fn buildSymbols(mut ast: &ast::AST, mut importer: Importer, mut owner: &symBuilder): (&SymTab, []log::Log) {
17+
fn buildSymbols(importPath: str, mut ast: &ast::AST, mut importer: Importer, mut owner: &symBuilder): (&SymTab, []log::Log) {
1818
mut sb := &symBuilder{
19+
importPath: importPath,
1920
ast: ast,
2021
importer: importer,
2122
owner: owner,
@@ -44,10 +45,18 @@ fn collectImplicitImports(mut s: &sema, mut file: &SymTab) {
4445
}
4546

4647
fn analyzePackage(mut files: []&ast::AST, mut importer: Importer, flags: int): (&Package, []log::Log) {
48+
// Select import path for the root package.
49+
// If there is no module, use "." as import path.
50+
// If we have module, use the module root name as import path.
51+
mut importPath := "."
52+
if importer != nil {
53+
importPath = getModName(importer)
54+
}
55+
4756
// Build symbol tables of files.
4857
mut tables := make([]&SymTab, 0, len(files))
4958
for (_, mut f) in files {
50-
mut table, mut errors := buildSymbols(f, importer, nil)
59+
mut table, mut errors := buildSymbols(importPath, f, importer, nil)
5160
if len(errors) > 0 {
5261
ret nil, errors
5362
}

std/jule/sema/sym.jule

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD 3-Clause
33
// license that can be found in the LICENSE file.
44

5+
use "std/conv"
56
use "std/jule"
67
use "std/jule/ast"
78
use "std/jule/build"
@@ -289,11 +290,12 @@ fn buildImpl(mut decl: &ast::Impl): &Impl {
289290
// Just builds symbols, not analyze metadata
290291
// like struct's implemented traits.
291292
struct symBuilder {
292-
owner: &symBuilder
293-
importer: Importer
294-
errors: []log::Log
295-
ast: &ast::AST
296-
table: &SymTab
293+
owner: &symBuilder
294+
importPath: str // Import path, this symBuilder created for.
295+
importer: Importer
296+
errors: []log::Log
297+
ast: &ast::AST
298+
table: &SymTab
297299
}
298300

299301
impl symBuilder {
@@ -369,20 +371,46 @@ impl symBuilder {
369371
// Designed for non-std package paths.
370372
// Returns empty string if error occurs.
371373
fn checkAbsPath(mut &self, mut filepath: str, mut decl: &ast::Use): str {
372-
modPath := self.importer.GetModPath()
374+
// If there is no module, no common directories.
375+
// For the local packages, the root package needs a module.
376+
mut modPath := self.importer.GetModPath()
373377
if len(modPath) == 0 {
374378
self.pushErr(decl.Path, log::ModuleNotFound)
375379
self.pushSuggestion(log::UseModInit)
376380
ret ""
377381
}
378382

383+
// Get module name.
384+
modName := getModNameFromPath(modPath)
385+
386+
// Get module name of the filepath.
387+
mut filepathModName := filepath
388+
i := strings::IndexByte(filepath, os::PathSeparator)
389+
if i > 0 {
390+
filepathModName = filepath[:i]
391+
}
392+
393+
// All import filepaths are must be start with module name.
394+
if modName != filepathModName {
395+
self.pushErr(decl.Path, "import path must use the root name of the module")
396+
self.pushSuggestion("module name of this package is: " + conv::Quote(modName))
397+
ret ""
398+
}
399+
400+
// To handle absolute package path correct,
401+
// select the previous directory of the module.
402+
// Because filepath is already starts with the module path.
403+
modPath = filepath::Dir(modPath)
404+
405+
// Join filepath with the absolute module path and
406+
// make sure we have an absolue path to the package.
379407
filepath = filepath::Join(modPath, filepath)
380408
filepath = filepath::Abs(filepath) else {
381409
self.pushErr(decl.Path, log::UseNotFound, decl.Path.Kind)
382410
ret ""
383411
}
384412

385-
// Exist?
413+
// Check the absolute path is exist and a directory (package).
386414
info := os::Stat(filepath) else {
387415
self.pushErr(decl.Path, log::UseNotFound, decl.Path.Kind)
388416
ret ""
@@ -435,7 +463,7 @@ impl symBuilder {
435463
}
436464
std = parts[0] == "std"
437465
for _, part in parts {
438-
if part == "" || jule::IsBlank(part) {
466+
if part == "" || jule::IsBlank(part) || strings::ContainsRune(part, '.') {
439467
self.pushErr(decl.Path, log::InvalidImportPath, decl.Path.Kind)
440468
ret false, ""
441469
}
@@ -502,63 +530,32 @@ impl symBuilder {
502530
ret false
503531
}
504532

505-
fn getAsLinkPath(mut &self, mut path: str): str {
506-
mut sb := strings::Builder{}
507-
sb.Grow(len(path))
508-
stdlib := build::PathStdlib()
509-
if strings::HasPrefix(path, stdlib) {
510-
path = path[len(stdlib):] // cut absolute path prefix
511-
sb.WriteStr(`"std`)!
512-
sb.WriteStr(strings::ReplaceAll(path, str(filepath::Separator), jule::ImportPathSep))!
513-
sb.WriteByte('"')!
514-
ret sb.Str()
515-
}
516-
517-
root := filepath::Abs(self.importer.GetModPath()) else { use "" }
518-
path = path[len(root):]
519-
if len(path) == 0 {
520-
path = filepath::Base(root)
521-
} else if path[0] == filepath::Separator {
522-
path = path[1:]
523-
}
524-
sb.WriteByte('"')!
525-
sb.WriteStr(strings::ReplaceAll(path, str(filepath::Separator), jule::ImportPathSep))!
526-
sb.WriteByte('"')!
527-
ret sb.Str()
528-
}
529-
530533
fn pushCycleError(mut &self, sb: &symBuilder, path: str, mut &message: *strings::Builder) {
531534
const Padding = 7
532-
refersTo := log::Logf(
533-
log::RefersTo,
534-
self.getAsLinkPath(sb.table.File.Dir()),
535-
self.getAsLinkPath(path))
535+
refersTo := log::Logf(log::RefersTo,
536+
"\""+sb.importPath+"\"",
537+
"\""+path+"\"")
536538
message.WriteStr(strings::Repeat(" ", Padding))!
537539
message.WriteStr(refersTo)!
538540
message.WriteByte('\n')!
539541
}
540542

541543
fn pushCrossCycleError(mut &self, target: &symBuilder, imp: &ImportInfo, errorToken: &token::Token) {
542544
mut message := strings::Builder{}
543-
message.Grow(1 << 5)
544-
self.pushCycleError(self, imp.Path, &message)
545-
mut owner := self.owner
546-
mut old := self
547-
for owner.owner != nil {
548-
self.pushCycleError(old.owner, old.table.File.Dir(), &message)
549-
if owner.owner == target {
550-
self.pushCycleError(target, owner.table.File.Dir(), &message)
545+
self.pushCycleError(self, imp.LinkPath, &message)
546+
mut owner, mut old := self.owner, self
547+
for owner != nil; owner, old = owner.owner, owner {
548+
self.pushCycleError(old.owner, old.importPath, &message)
549+
if owner == target {
551550
break
552551
}
553-
old = owner
554-
owner = owner.owner
555552
}
556553
self.pushErr(errorToken, log::PkgIllegalCrossCycle, message.Str())
557554
}
558555

559556
fn checkImportCycles(mut &self, imp: &ImportInfo, decl: &ast::Use): bool {
560557
if imp.Path == self.table.File.Dir() {
561-
self.pushErr(decl.Token, log::PkgIllegalCycleRefersItself, self.getAsLinkPath(imp.Path))
558+
self.pushErr(decl.Token, log::PkgIllegalCycleRefersItself, imp.LinkPath)
562559
ret false
563560
}
564561
if self.owner == nil {
@@ -644,7 +641,7 @@ impl symBuilder {
644641

645642
for (_, mut ast) in asts {
646643
mut table := (&SymTab)(nil)
647-
table, errors = buildSymbols(ast, self.importer, self)
644+
table, errors = buildSymbols(imp.LinkPath, ast, self.importer, self)
648645
// Break import if file has error(s).
649646
if len(errors) > 0 {
650647
self.errors = append(self.errors, errors...)
@@ -793,4 +790,22 @@ impl symBuilder {
793790
// See developer reference (6).
794791
fn isImplicitImport(imp: &ImportInfo): bool {
795792
ret imp.Decl.Token == nil
793+
}
794+
795+
// Returns module name by module path provided by importer.
796+
// Returns "." if module path is empty.
797+
fn getModName(importer: Importer): str {
798+
ret getModNameFromPath(importer.GetModPath())
799+
}
800+
801+
// Returns module name by module path.
802+
// Returns "." if module path is empty.
803+
fn getModNameFromPath(path: str): str {
804+
// This path is the absolute path, it should be.
805+
// So, the module name is the base name of the absolue module path.
806+
//
807+
// Example:
808+
// "foo" -> "foo"
809+
// "foo/bar/baz" -> "baz"
810+
ret filepath::Base(path)
796811
}

0 commit comments

Comments
 (0)