symbol_table.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package tengo
  2. // SymbolScope represents a symbol scope.
  3. type SymbolScope string
  4. // List of symbol scopes
  5. const (
  6. ScopeGlobal SymbolScope = "GLOBAL"
  7. ScopeLocal SymbolScope = "LOCAL"
  8. ScopeBuiltin SymbolScope = "BUILTIN"
  9. ScopeFree SymbolScope = "FREE"
  10. )
  11. // Symbol represents a symbol in the symbol table.
  12. type Symbol struct {
  13. Name string
  14. Scope SymbolScope
  15. Index int
  16. LocalAssigned bool // if the local symbol is assigned at least once
  17. }
  18. // SymbolTable represents a symbol table.
  19. type SymbolTable struct {
  20. parent *SymbolTable
  21. block bool
  22. store map[string]*Symbol
  23. numDefinition int
  24. maxDefinition int
  25. freeSymbols []*Symbol
  26. builtinSymbols []*Symbol
  27. }
  28. // NewSymbolTable creates a SymbolTable.
  29. func NewSymbolTable() *SymbolTable {
  30. return &SymbolTable{
  31. store: make(map[string]*Symbol),
  32. }
  33. }
  34. // Define adds a new symbol in the current scope.
  35. func (t *SymbolTable) Define(name string) *Symbol {
  36. symbol := &Symbol{Name: name, Index: t.nextIndex()}
  37. t.numDefinition++
  38. if t.Parent(true) == nil {
  39. symbol.Scope = ScopeGlobal
  40. // if symbol is defined in a block of global scope, symbol index must
  41. // be tracked at the root-level table instead.
  42. if p := t.parent; p != nil {
  43. for p.parent != nil {
  44. p = p.parent
  45. }
  46. t.numDefinition--
  47. p.numDefinition++
  48. }
  49. } else {
  50. symbol.Scope = ScopeLocal
  51. }
  52. t.store[name] = symbol
  53. t.updateMaxDefs(symbol.Index + 1)
  54. return symbol
  55. }
  56. // DefineBuiltin adds a symbol for builtin function.
  57. func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol {
  58. if t.parent != nil {
  59. return t.parent.DefineBuiltin(index, name)
  60. }
  61. symbol := &Symbol{
  62. Name: name,
  63. Index: index,
  64. Scope: ScopeBuiltin,
  65. }
  66. t.store[name] = symbol
  67. t.builtinSymbols = append(t.builtinSymbols, symbol)
  68. return symbol
  69. }
  70. // Resolve resolves a symbol with a given name.
  71. func (t *SymbolTable) Resolve(
  72. name string,
  73. recur bool,
  74. ) (*Symbol, int, bool) {
  75. symbol, ok := t.store[name]
  76. if ok {
  77. // symbol can be used if
  78. if symbol.Scope != ScopeLocal || // it's not of local scope, OR,
  79. symbol.LocalAssigned || // it's assigned at least once, OR,
  80. recur { // it's defined in higher level
  81. return symbol, 0, true
  82. }
  83. }
  84. if t.parent == nil {
  85. return nil, 0, false
  86. }
  87. symbol, depth, ok := t.parent.Resolve(name, true)
  88. if !ok {
  89. return nil, 0, false
  90. }
  91. depth++
  92. // if symbol is defined in parent table and if it's not global/builtin
  93. // then it's free variable.
  94. if !t.block && depth > 0 &&
  95. symbol.Scope != ScopeGlobal &&
  96. symbol.Scope != ScopeBuiltin {
  97. return t.defineFree(symbol), depth, true
  98. }
  99. return symbol, depth, true
  100. }
  101. // Fork creates a new symbol table for a new scope.
  102. func (t *SymbolTable) Fork(block bool) *SymbolTable {
  103. return &SymbolTable{
  104. store: make(map[string]*Symbol),
  105. parent: t,
  106. block: block,
  107. }
  108. }
  109. // Parent returns the outer scope of the current symbol table.
  110. func (t *SymbolTable) Parent(skipBlock bool) *SymbolTable {
  111. if skipBlock && t.block {
  112. return t.parent.Parent(skipBlock)
  113. }
  114. return t.parent
  115. }
  116. // MaxSymbols returns the total number of symbols defined in the scope.
  117. func (t *SymbolTable) MaxSymbols() int {
  118. return t.maxDefinition
  119. }
  120. // FreeSymbols returns free symbols for the scope.
  121. func (t *SymbolTable) FreeSymbols() []*Symbol {
  122. return t.freeSymbols
  123. }
  124. // BuiltinSymbols returns builtin symbols for the scope.
  125. func (t *SymbolTable) BuiltinSymbols() []*Symbol {
  126. if t.parent != nil {
  127. return t.parent.BuiltinSymbols()
  128. }
  129. return t.builtinSymbols
  130. }
  131. // Names returns the name of all the symbols.
  132. func (t *SymbolTable) Names() []string {
  133. var names []string
  134. for name := range t.store {
  135. names = append(names, name)
  136. }
  137. return names
  138. }
  139. func (t *SymbolTable) nextIndex() int {
  140. if t.block {
  141. return t.parent.nextIndex() + t.numDefinition
  142. }
  143. return t.numDefinition
  144. }
  145. func (t *SymbolTable) updateMaxDefs(numDefs int) {
  146. if numDefs > t.maxDefinition {
  147. t.maxDefinition = numDefs
  148. }
  149. if t.block {
  150. t.parent.updateMaxDefs(numDefs)
  151. }
  152. }
  153. func (t *SymbolTable) defineFree(original *Symbol) *Symbol {
  154. // TODO: should we check duplicates?
  155. t.freeSymbols = append(t.freeSymbols, original)
  156. symbol := &Symbol{
  157. Name: original.Name,
  158. Index: len(t.freeSymbols) - 1,
  159. Scope: ScopeFree,
  160. }
  161. t.store[original.Name] = symbol
  162. return symbol
  163. }