Add some initial analyzer tests for units
This commit is contained in:
parent
afe3683c2a
commit
78fa0f703d
|
@ -5,6 +5,7 @@ import "fmt"
|
|||
import "errors"
|
||||
import "os/exec"
|
||||
import "path/filepath"
|
||||
import "github.com/google/uuid"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/llvm"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/lexer"
|
||||
import "git.tebibyte.media/sashakoshka/fspl/entity"
|
||||
|
@ -21,21 +22,8 @@ type Compiler struct {
|
|||
}
|
||||
|
||||
func (this *Compiler) CompileUnit (address entity.Address) error {
|
||||
_, isFile := address.SourceFile()
|
||||
_, isModule := address.Module()
|
||||
if !isFile && !isModule {
|
||||
return errors.New(fmt.Sprintf (
|
||||
"%v is not a module, nor a source file",
|
||||
address))
|
||||
}
|
||||
|
||||
var syntaxTree fsplParser.Tree
|
||||
var err error
|
||||
if isModule {
|
||||
syntaxTree, err = this.ParseModule(address)
|
||||
} else {
|
||||
syntaxTree, err = this.ParseSourceFile(address)
|
||||
}
|
||||
_, err := this.ParseUnit(&syntaxTree, address, false)
|
||||
if err != nil { return err }
|
||||
|
||||
// analyze syntax tree
|
||||
|
@ -88,28 +76,59 @@ func (this *Compiler) CompileUnit (address entity.Address) error {
|
|||
}
|
||||
}
|
||||
|
||||
func (this *Compiler) ParseModule (address entity.Address) (fsplParser.Tree, error) {
|
||||
func (this *Compiler) ParseUnit (
|
||||
syntaxTree *fsplParser.Tree,
|
||||
address entity.Address,
|
||||
skim bool,
|
||||
) (
|
||||
*fsplParser.UnitInfo,
|
||||
error,
|
||||
) {
|
||||
_, isFile := address.SourceFile()
|
||||
_, isModule := address.Module()
|
||||
if !isFile && !isModule {
|
||||
return nil, errors.New(fmt.Sprintf (
|
||||
"%v is not a module, nor a source file",
|
||||
address))
|
||||
}
|
||||
|
||||
if isModule {
|
||||
return this.ParseModule(syntaxTree, address, skim)
|
||||
} else {
|
||||
return this.ParseSourceFile(syntaxTree, address, skim)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Compiler) ParseModule (
|
||||
syntaxTree *fsplParser.Tree,
|
||||
address entity.Address,
|
||||
skim bool,
|
||||
) (
|
||||
*fsplParser.UnitInfo,
|
||||
error,
|
||||
) {
|
||||
modulePath, isModule := address.Module()
|
||||
var syntaxTree fsplParser.Tree
|
||||
if !isModule {
|
||||
return syntaxTree, errors.New(fmt.Sprintf("%v is not a module", address))
|
||||
return nil, errors.New(fmt.Sprintf("%v is not a module", address))
|
||||
}
|
||||
|
||||
// parse module metadata file
|
||||
var metaTree metaParser.Tree
|
||||
lx, err := lexer.LexFile(filepath.Join(modulePath, "fspl.mod"))
|
||||
if err != nil { return syntaxTree, err }
|
||||
if err != nil { return nil, err }
|
||||
err = metaTree.Parse(lx)
|
||||
if err != nil { return syntaxTree, err }
|
||||
if err != nil { return nil, err }
|
||||
|
||||
// ensure metadata is well formed
|
||||
// FIXME: sort this map alphabetically so the result of the compiler is
|
||||
// deterministic
|
||||
dependencies := make(map[string] *entity.Dependency)
|
||||
for _, dependency := range metaTree.Dependencies {
|
||||
nickname := dependency.Nickname
|
||||
if nickname == "" {
|
||||
newNickname, ok := dependency.Address.Nickname()
|
||||
if !ok {
|
||||
return syntaxTree, ferrors.Errorf (
|
||||
return nil, ferrors.Errorf (
|
||||
dependency.Position,
|
||||
"cannot generate nickname for %v, " +
|
||||
"please add one after the address",
|
||||
|
@ -118,7 +137,7 @@ func (this *Compiler) ParseModule (address entity.Address) (fsplParser.Tree, err
|
|||
nickname = newNickname
|
||||
}
|
||||
if previous, exists := dependencies[nickname]; exists {
|
||||
return syntaxTree, ferrors.Errorf (
|
||||
return nil, ferrors.Errorf (
|
||||
dependency.Position,
|
||||
"unit with nickname %v already listed at %v",
|
||||
nickname, previous.Position)
|
||||
|
@ -126,36 +145,61 @@ func (this *Compiler) ParseModule (address entity.Address) (fsplParser.Tree, err
|
|||
dependencies[nickname] = dependency
|
||||
}
|
||||
|
||||
// parse dependency units
|
||||
unitInfo := fsplParser.UnitInfo {
|
||||
UUID: metaTree.UUID,
|
||||
Dependencies: make(map[string] uuid.UUID),
|
||||
}
|
||||
for nickname, dependency := range dependencies {
|
||||
dependencyInfo, err := this.ParseUnit(syntaxTree, dependency.Address, true)
|
||||
if err != nil { return nil, err }
|
||||
unitInfo.Dependencies[nickname] = dependencyInfo.UUID
|
||||
}
|
||||
|
||||
// parse all files in the module
|
||||
entries, err := os.ReadDir(modulePath)
|
||||
if err != nil { return syntaxTree, err }
|
||||
if err != nil { return nil, err }
|
||||
for _, entry := range entries {
|
||||
lx, err := lexer.LexFile(filepath.Join (
|
||||
modulePath,
|
||||
entry.Name()))
|
||||
if err != nil { return syntaxTree, err }
|
||||
err = syntaxTree.Parse(lx)
|
||||
if err != nil { return syntaxTree, err }
|
||||
if err != nil { return nil, err }
|
||||
if skim {
|
||||
err = syntaxTree.ParseDependency(unitInfo, lx)
|
||||
} else {
|
||||
err = syntaxTree.Parse(unitInfo, lx)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
}
|
||||
// TODO
|
||||
// have a ParseDependency method on fsplParser.Tree that parses
|
||||
// in a dependency, and parse in each dependency. Would need
|
||||
// extra fields in top-level entities for a module namespace.
|
||||
return syntaxTree, nil
|
||||
return &unitInfo, nil
|
||||
}
|
||||
|
||||
func (this *Compiler) ParseSourceFile (address entity.Address) (fsplParser.Tree, error) {
|
||||
func (this *Compiler) ParseSourceFile (
|
||||
syntaxTree *fsplParser.Tree,
|
||||
address entity.Address,
|
||||
skim bool,
|
||||
) (
|
||||
*fsplParser.UnitInfo,
|
||||
error,
|
||||
) {
|
||||
filePath, isFile := address.Module()
|
||||
var syntaxTree fsplParser.Tree
|
||||
if !isFile {
|
||||
return syntaxTree, errors.New(fmt.Sprintf("%v is not a source file", address))
|
||||
return nil, errors.New(fmt.Sprintf("%v is not a source file", address))
|
||||
}
|
||||
|
||||
unitInfo := fsplParser.UnitInfo {
|
||||
UUID: address.UUID(),
|
||||
}
|
||||
|
||||
lx, err := lexer.LexFile(filePath)
|
||||
if err != nil { return syntaxTree, err }
|
||||
err = syntaxTree.Parse(lx)
|
||||
if err != nil { return syntaxTree, err }
|
||||
return syntaxTree, nil
|
||||
if err != nil { return nil, err }
|
||||
if skim {
|
||||
err = syntaxTree.ParseDependency(unitInfo, lx)
|
||||
} else {
|
||||
err = syntaxTree.Parse(unitInfo, lx)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
return &unitInfo, nil
|
||||
}
|
||||
|
||||
func (this *Compiler) CompileIRModule (module *llvm.Module, filetype string) error {
|
||||
|
|
Loading…
Reference in New Issue