Skip to content

Commit ded29a2

Browse files
committed
sema: fix and refactor import handling
1 parent 7cb135b commit ded29a2

File tree

1 file changed

+79
-137
lines changed

1 file changed

+79
-137
lines changed

std/jule/sema/sym.jule

Lines changed: 79 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -322,102 +322,10 @@ impl symBuilder {
322322
unsafe { pushSuggestion(&self.errors[len(self.errors)-1], fmt, args...) }
323323
}
324324

325-
fn checkCppUseDeclPath(mut *self, decl: &ast::Use, path: str): (ok: bool) {
326-
ext := filepath::Ext(path)
327-
if !build::IsValidHeaderExt(ext) && !build::IsValidCppExt(ext) {
328-
self.pushErr(decl.Token, "invalid C/C++ extension: "+conv::Quote(ext))
329-
ret false
330-
}
331-
332-
// Exist?
333-
info := os::Stat(path) else {
334-
self.pushErr(decl.Token, "path not found or cannot be accessed: "+decl.Path.Kind)
335-
ret false
336-
}
337-
if !info.Mode().IsRegular() {
338-
self.pushErr(decl.Token, "path not found or cannot be accessed: "+decl.Path.Kind)
339-
ret false
340-
}
341-
342-
ret true
343-
}
344-
345-
fn buildCppHeaderImport(mut *self, mut decl: &ast::Use): &ImportInfo {
346-
mut path := decl.Path.Kind[1 : len(decl.Path.Kind)-1] // remove quotes
347-
348-
if !build::IsStdHeaderPath(path) {
349-
// If there is no module, no common directories.
350-
// For the local packages, the root package needs a module.
351-
mut mod := self.importer.GetMod()
352-
if mod == nil {
353-
self.pushErr(decl.Path, "module not found")
354-
self.pushSuggestion(`run "julec mod init <modulename>" to initialize a bind module in the current directory`)
355-
ret nil
356-
}
357-
358-
// Take module name and submodule path from the path.
359-
pathModName, (path) := splitModuleNameFromFilepath(path)
360-
361-
// All import filepaths are must be start with module name.
362-
if mod.Name != pathModName {
363-
self.pushErr(decl.Path, "import path must use the root name of the module")
364-
self.pushSuggestion("module name of this package is: " + conv::Quote(mod.Name))
365-
ret nil
366-
}
367-
368-
// Join path with the absolute module path and
369-
// make sure we have an absolute path to the package.
370-
path = filepath::Join(mod.Path, path)
371-
path = filepath::Abs(path) else {
372-
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
373-
ret nil
374-
}
375-
376-
mut ok := self.checkCppUseDeclPath(decl, path)
377-
if !ok {
378-
ret nil
379-
}
380-
381-
// Set to absolute path for correct include path.
382-
path = filepath::Abs(path) else {
383-
self.pushErr(decl.Token, "path not found or cannot be accessed: "+decl.Path.Kind)
384-
use ""
385-
}
386-
}
387-
388-
ret &ImportInfo{
389-
Decl: decl,
390-
Path: path,
391-
LinkPath: decl.Path.Kind,
392-
Bind: true,
393-
Std: false,
394-
Package: nil, // Cpp headers haven't symbol table.
395-
}
396-
}
397-
398325
// Checks and returns absolute path of import filepath.
399326
// Designed for non-std package paths.
400327
// Returns empty string if error occurs.
401-
fn checkAbsPath(mut &self, mut filepath: str, mut decl: &ast::Use): str {
402-
// If there is no module, no common directories.
403-
// For the local packages, the root package needs a module.
404-
mut mod := self.importer.GetMod()
405-
if mod == nil {
406-
self.pushErr(decl.Path, "module not found")
407-
self.pushSuggestion(`run "julec mod init <modulename>" to initialize a module in the current directory`)
408-
ret ""
409-
}
410-
411-
// Take module name and submodule path from the filepath.
412-
filepathModName, filepath := splitModuleNameFromFilepath(filepath)
413-
414-
// All import filepaths are must be start with module name.
415-
if mod.Name != filepathModName {
416-
self.pushErr(decl.Path, "import path must use the root name of the module")
417-
self.pushSuggestion("module name of this package is: " + conv::Quote(mod.Name))
418-
ret ""
419-
}
420-
328+
fn checkAbsPath(mut &self, mut filepath: str, mut decl: &ast::Use, mod: &mod::Mod): str {
421329
// Join filepath with the absolute module path and
422330
// make sure we have an absolute path to the package.
423331
filepath = filepath::Join(mod.Path, filepath)
@@ -426,72 +334,84 @@ impl symBuilder {
426334
ret ""
427335
}
428336

429-
// Check the absolute path is exist and a directory (package).
430-
info := os::Stat(filepath) else {
431-
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
432-
ret ""
433-
}
434-
if !info.IsDir() {
435-
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
436-
ret ""
437-
}
438-
439337
ret filepath
440338
}
441339

442340
// Same as the [checkAbsPath] method but designed for std package paths.
443341
fn checkStdAbsPath(mut &self, mut filepath: str, mut decl: &ast::Use): str {
444-
if filepath == "std" {
342+
if filepath == "" {
445343
self.pushErr(decl.Path, "invalid import path: "+decl.Path.Kind)
446344
ret ""
447345
}
448-
filepath = filepath[len("std")+1:] // cut "std" + pathsep prefix
449346
filepath = filepath::Join(build::PathStdlib(), filepath)
450347
filepath = filepath::Abs(filepath) else {
451348
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
452349
ret ""
453350
}
454351

455-
// Exist?
456-
info := os::Stat(filepath) else {
457-
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
458-
ret ""
459-
}
460-
if !info.IsDir() {
461-
self.pushErr(decl.Path, "path not found or cannot be accessed: "+decl.Path.Kind)
462-
ret ""
463-
}
464-
465352
ret filepath
466353
}
467354

468355
// Checks import path and returns as filepath if no error exist.
469356
fn checkImpPath(mut &self, mut decl: &ast::Use): (std: bool, filepath: str) {
470357
path := decl.Path.Kind[1 : len(decl.Path.Kind)-1] // remove quotes
471-
if strings::HasSuffix(path, jule::ImportPathSep) {
472-
self.pushErr(decl.Path, "invalid import path: "+decl.Path.Kind)
473-
ret
358+
if decl.Bind && build::IsStdHeaderPath(path) {
359+
ret false, path
474360
}
475-
parts := strings::Split(path, jule::ImportPathSep)
476-
if len(parts) == 0 {
361+
362+
// Take module name and submodule path from the import path.
363+
pathModName, submodulePath := splitModuleNameFromFilepath(path)
364+
std = pathModName == build::ModStdlib().Name
365+
366+
filepath = checkImportPathValidity(submodulePath)
367+
if filepath == "" {
477368
self.pushErr(decl.Path, "invalid import path: "+decl.Path.Kind)
478-
ret
479-
}
480-
std = parts[0] == "std"
481-
for _, part in parts {
482-
if part == "" || jule::IsBlank(part) || strings::ContainsRune(part, '.') {
483-
self.pushErr(decl.Path, "invalid import path: "+decl.Path.Kind)
484-
ret false, ""
485-
}
486-
filepath = filepath::Join(filepath, part)
369+
ret false, ""
487370
}
488371

489372
// build absolute path
490373
if std {
491374
filepath = self.checkStdAbsPath(filepath, decl)
492375
} else {
493-
filepath = self.checkAbsPath(filepath, decl)
376+
// If there is no module, no common directories.
377+
// For the local packages, the root package needs a module.
378+
mut mod := self.importer.GetMod()
379+
if mod == nil {
380+
self.pushErr(decl.Path, "module not found")
381+
self.pushSuggestion(`run "julec mod init <modulename>" to initialize a module in the current directory`)
382+
ret false, ""
383+
}
384+
385+
// All import filepaths are must be start with module name.
386+
if mod.Name != pathModName {
387+
self.pushErr(decl.Path, "import path must use the root name of the module")
388+
self.pushSuggestion("module name of this package is: " + conv::Quote(mod.Name))
389+
ret false, ""
390+
}
391+
392+
filepath = self.checkAbsPath(filepath, decl, mod)
494393
}
394+
395+
if decl.Bind {
396+
ext := filepath::Ext(filepath)
397+
if !build::IsValidHeaderExt(ext) && !build::IsValidCppExt(ext) {
398+
self.pushErr(decl.Token, "invalid C/C++ extension: "+conv::Quote(ext))
399+
ret false, ""
400+
}
401+
}
402+
403+
// Exist?
404+
info := os::Stat(filepath) else {
405+
self.pushErr(decl.Token, "path not found or cannot be accessed: "+decl.Path.Kind)
406+
ret false, ""
407+
}
408+
exist := !decl.Bind && info.IsDir() ||
409+
decl.Bind && info.Mode().IsRegular()
410+
if !exist {
411+
self.pushErr(decl.Token, "path not found or cannot be accessed: "+decl.Path.Kind)
412+
ret false, ""
413+
}
414+
495415
ret
496416
}
497417

@@ -504,9 +424,6 @@ impl symBuilder {
504424
}
505425

506426
fn buildImport(mut &self, mut decl: &ast::Use): &ImportInfo {
507-
if decl.Bind {
508-
ret self.buildCppHeaderImport(decl)
509-
}
510427
std, filepath := self.checkImpPath(decl)
511428
if filepath == "" { // error occurred
512429
ret nil
@@ -516,11 +433,17 @@ impl symBuilder {
516433
Decl: decl,
517434
Path: filepath,
518435
LinkPath: decl.Path.Kind[1 : len(decl.Path.Kind)-1],
519-
Bind: false,
520436
Std: std,
521-
Package: &Package{
522-
Files: nil, // Appends by import algorithm.
523-
},
437+
}
438+
439+
if decl.Bind {
440+
imp.Bind = true
441+
imp.Package = nil // Cpp headers haven't symbol table.
442+
ret imp
443+
}
444+
445+
imp.Package = &Package{
446+
Files: nil, // Appends by import algorithm.
524447
}
525448
if decl.Alias != nil {
526449
imp.Alias = decl.Alias.Kind
@@ -827,4 +750,23 @@ fn splitModuleNameFromFilepath(filepath: str): (modName: str, submodulePath: str
827750
submodulePath = ""
828751
}
829752
ret
753+
}
754+
755+
// Checks validity of the import path and returns it as filepath.
756+
// Returns empty string if path is invalid.
757+
fn checkImportPathValidity(path: str): (filepath: str) {
758+
if strings::HasSuffix(path, jule::ImportPathSep) {
759+
ret ""
760+
}
761+
parts := strings::Split(path, jule::ImportPathSep)
762+
if len(parts) == 0 {
763+
ret ""
764+
}
765+
for _, part in parts {
766+
if part == "" || jule::IsBlank(part) || strings::ContainsAny(part, "\\") {
767+
ret ""
768+
}
769+
filepath = filepath::Join(filepath, part)
770+
}
771+
ret filepath
830772
}

0 commit comments

Comments
 (0)