2019-02-23 15:39:44 +00:00
|
|
|
package compiler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/d5/tengo/compiler/ast"
|
|
|
|
"github.com/d5/tengo/compiler/parser"
|
|
|
|
"github.com/d5/tengo/objects"
|
|
|
|
)
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
func (c *Compiler) checkCyclicImports(node ast.Node, modulePath string) error {
|
|
|
|
if c.modulePath == modulePath {
|
|
|
|
return c.errorf(node, "cyclic module import: %s", modulePath)
|
|
|
|
} else if c.parent != nil {
|
|
|
|
return c.parent.checkCyclicImports(node, modulePath)
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-02-23 15:39:44 +00:00
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
func (c *Compiler) compileModule(node ast.Node, moduleName, modulePath string, src []byte) (*objects.CompiledFunction, error) {
|
|
|
|
if err := c.checkCyclicImports(node, modulePath); err != nil {
|
2019-02-23 15:39:44 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
compiledModule, exists := c.loadCompiledModule(modulePath)
|
|
|
|
if exists {
|
|
|
|
return compiledModule, nil
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
modFile := c.file.Set().AddFile(moduleName, -1, len(src))
|
|
|
|
p := parser.NewParser(modFile, src, nil)
|
|
|
|
file, err := p.ParseFile()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
symbolTable := NewSymbolTable()
|
|
|
|
|
|
|
|
// inherit builtin functions
|
2019-03-05 22:08:54 +00:00
|
|
|
for _, sym := range c.symbolTable.BuiltinSymbols() {
|
|
|
|
symbolTable.DefineBuiltin(sym.Index, sym.Name)
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// no global scope for the module
|
|
|
|
symbolTable = symbolTable.Fork(false)
|
|
|
|
|
|
|
|
// compile module
|
2019-04-06 20:18:25 +00:00
|
|
|
moduleCompiler := c.fork(modFile, modulePath, symbolTable)
|
2019-02-23 15:39:44 +00:00
|
|
|
if err := moduleCompiler.Compile(file); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
// code optimization
|
|
|
|
moduleCompiler.optimizeFunc(node)
|
2019-02-23 15:39:44 +00:00
|
|
|
|
|
|
|
compiledFunc := moduleCompiler.Bytecode().MainFunction
|
|
|
|
compiledFunc.NumLocals = symbolTable.MaxSymbols()
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
c.storeCompiledModule(modulePath, compiledFunc)
|
|
|
|
|
2019-02-23 15:39:44 +00:00
|
|
|
return compiledFunc, nil
|
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
func (c *Compiler) loadCompiledModule(modulePath string) (mod *objects.CompiledFunction, ok bool) {
|
2019-02-23 15:39:44 +00:00
|
|
|
if c.parent != nil {
|
2019-04-06 20:18:25 +00:00
|
|
|
return c.parent.loadCompiledModule(modulePath)
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
mod, ok = c.compiledModules[modulePath]
|
2019-02-23 15:39:44 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
func (c *Compiler) storeCompiledModule(modulePath string, module *objects.CompiledFunction) {
|
2019-02-23 15:39:44 +00:00
|
|
|
if c.parent != nil {
|
2019-04-06 20:18:25 +00:00
|
|
|
c.parent.storeCompiledModule(modulePath, module)
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-06 20:18:25 +00:00
|
|
|
c.compiledModules[modulePath] = module
|
2019-02-23 15:39:44 +00:00
|
|
|
}
|