-
Notifications
You must be signed in to change notification settings - Fork 0
/
compiler_module.go
116 lines (93 loc) · 2.54 KB
/
compiler_module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package compiler
import (
"fmt"
"io/ioutil"
"strings"
"github.com/d5/tengo/compiler/parser"
"github.com/d5/tengo/compiler/source"
"github.com/d5/tengo/objects"
)
var (
fileSet = source.NewFileSet()
)
func (c *Compiler) compileModule(moduleName string) (*objects.CompiledModule, error) {
compiledModule, exists := c.loadCompiledModule(moduleName)
if exists {
return compiledModule, nil
}
// read module source from loader
var moduleSrc []byte
if c.moduleLoader == nil {
// default loader: read from local file
if !strings.HasSuffix(moduleName, ".tengo") {
moduleName += ".tengo"
}
if err := c.checkCyclicImports(moduleName); err != nil {
return nil, err
}
var err error
moduleSrc, err = ioutil.ReadFile(moduleName)
if err != nil {
return nil, err
}
} else {
if err := c.checkCyclicImports(moduleName); err != nil {
return nil, err
}
var err error
moduleSrc, err = c.moduleLoader(moduleName)
if err != nil {
return nil, err
}
}
compiledModule, err := c.doCompileModule(moduleName, moduleSrc)
if err != nil {
return nil, err
}
c.storeCompiledModule(moduleName, compiledModule)
return compiledModule, nil
}
func (c *Compiler) checkCyclicImports(moduleName string) error {
if c.moduleName == moduleName {
return fmt.Errorf("cyclic module import: %s", moduleName)
} else if c.parent != nil {
return c.parent.checkCyclicImports(moduleName)
}
return nil
}
func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.CompiledModule, error) {
p := parser.NewParser(fileSet.AddFile(moduleName, -1, len(src)), src, nil)
file, err := p.ParseFile()
if err != nil {
return nil, err
}
symbolTable := NewSymbolTable()
globals := make(map[string]int)
moduleCompiler := c.fork(moduleName, symbolTable)
if err := moduleCompiler.Compile(file); err != nil {
return nil, err
}
for _, name := range symbolTable.Names() {
symbol, _, _ := symbolTable.Resolve(name)
if symbol.Scope == ScopeGlobal {
globals[name] = symbol.Index
}
}
return &objects.CompiledModule{
Instructions: moduleCompiler.Bytecode().Instructions,
Globals: globals,
}, nil
}
func (c *Compiler) loadCompiledModule(moduleName string) (mod *objects.CompiledModule, ok bool) {
if c.parent != nil {
return c.parent.loadCompiledModule(moduleName)
}
mod, ok = c.compiledModules[moduleName]
return
}
func (c *Compiler) storeCompiledModule(moduleName string, module *objects.CompiledModule) {
if c.parent != nil {
c.parent.storeCompiledModule(moduleName, module)
}
c.compiledModules[moduleName] = module
}