compiler.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. package goja
  2. import (
  3. "fmt"
  4. "github.com/dop251/goja/ast"
  5. "github.com/dop251/goja/file"
  6. "strconv"
  7. )
  8. const (
  9. blockLoop = iota
  10. blockTry
  11. blockBranch
  12. blockSwitch
  13. blockWith
  14. )
  15. type CompilerError struct {
  16. Message string
  17. File *SrcFile
  18. Offset int
  19. }
  20. type CompilerSyntaxError struct {
  21. CompilerError
  22. }
  23. type CompilerReferenceError struct {
  24. CompilerError
  25. }
  26. type srcMapItem struct {
  27. pc int
  28. srcPos int
  29. }
  30. type Program struct {
  31. code []instruction
  32. values []Value
  33. funcName string
  34. src *SrcFile
  35. srcMap []srcMapItem
  36. }
  37. type compiler struct {
  38. p *Program
  39. scope *scope
  40. block *block
  41. blockStart int
  42. enumGetExpr compiledEnumGetExpr
  43. evalVM *vm
  44. }
  45. type scope struct {
  46. names map[string]uint32
  47. outer *scope
  48. strict bool
  49. eval bool
  50. lexical bool
  51. dynamic bool
  52. accessed bool
  53. argsNeeded bool
  54. thisNeeded bool
  55. namesMap map[string]string
  56. lastFreeTmp int
  57. }
  58. type block struct {
  59. typ int
  60. label string
  61. needResult bool
  62. cont int
  63. breaks []int
  64. conts []int
  65. outer *block
  66. }
  67. func (c *compiler) leaveBlock() {
  68. lbl := len(c.p.code)
  69. for _, item := range c.block.breaks {
  70. c.p.code[item] = jump(lbl - item)
  71. }
  72. if c.block.typ == blockLoop {
  73. for _, item := range c.block.conts {
  74. c.p.code[item] = jump(c.block.cont - item)
  75. }
  76. }
  77. c.block = c.block.outer
  78. }
  79. func (e *CompilerSyntaxError) Error() string {
  80. if e.File != nil {
  81. return fmt.Sprintf("SyntaxError: %s at %s", e.Message, e.File.Position(e.Offset))
  82. }
  83. return fmt.Sprintf("SyntaxError: %s", e.Message)
  84. }
  85. func (e *CompilerReferenceError) Error() string {
  86. return fmt.Sprintf("ReferenceError: %s", e.Message)
  87. }
  88. func (c *compiler) newScope() {
  89. strict := false
  90. if c.scope != nil {
  91. strict = c.scope.strict
  92. }
  93. c.scope = &scope{
  94. outer: c.scope,
  95. names: make(map[string]uint32),
  96. strict: strict,
  97. namesMap: make(map[string]string),
  98. }
  99. }
  100. func (c *compiler) popScope() {
  101. c.scope = c.scope.outer
  102. }
  103. func newCompiler() *compiler {
  104. c := &compiler{
  105. p: &Program{},
  106. }
  107. c.enumGetExpr.init(c, file.Idx(0))
  108. c.newScope()
  109. c.scope.dynamic = true
  110. c.evalVM = New().vm
  111. return c
  112. }
  113. func (p *Program) defineLiteralValue(val Value) uint32 {
  114. for idx, v := range p.values {
  115. if v.SameAs(val) {
  116. return uint32(idx)
  117. }
  118. }
  119. idx := uint32(len(p.values))
  120. p.values = append(p.values, val)
  121. return idx
  122. }
  123. func (p *Program) dumpCode(logger func(format string, args ...interface{})) {
  124. p._dumpCode("", logger)
  125. }
  126. func (p *Program) _dumpCode(indent string, logger func(format string, args ...interface{})) {
  127. logger("values: %+v", p.values)
  128. for pc, ins := range p.code {
  129. logger("%s %d: %T(%v)", indent, pc, ins, ins)
  130. if f, ok := ins.(*newFunc); ok {
  131. f.prg._dumpCode(indent+">", logger)
  132. }
  133. }
  134. }
  135. func (p *Program) sourceOffset(pc int) int {
  136. // TODO use sort.Search()
  137. for i, item := range p.srcMap {
  138. if item.pc > pc {
  139. if i > 0 {
  140. return p.srcMap[i-1].srcPos
  141. }
  142. return 0
  143. }
  144. }
  145. return p.srcMap[len(p.srcMap)-1].srcPos
  146. }
  147. func (s *scope) isFunction() bool {
  148. if !s.lexical {
  149. return s.outer != nil
  150. }
  151. return s.outer.isFunction()
  152. }
  153. func (s *scope) lookupName(name string) (idx uint32, found, noDynamics bool) {
  154. var level uint32 = 0
  155. noDynamics = true
  156. for curScope := s; curScope != nil; curScope = curScope.outer {
  157. if curScope != s {
  158. curScope.accessed = true
  159. }
  160. if curScope.dynamic {
  161. noDynamics = false
  162. } else {
  163. var mapped string
  164. if m, exists := curScope.namesMap[name]; exists {
  165. mapped = m
  166. } else {
  167. mapped = name
  168. }
  169. if i, exists := curScope.names[mapped]; exists {
  170. idx = i | (level << 24)
  171. found = true
  172. return
  173. }
  174. }
  175. if name == "arguments" && !s.lexical && s.isFunction() {
  176. s.argsNeeded = true
  177. s.accessed = true
  178. idx, _ = s.bindName(name)
  179. found = true
  180. return
  181. }
  182. level++
  183. }
  184. return
  185. }
  186. func (s *scope) bindName(name string) (uint32, bool) {
  187. if s.lexical {
  188. return s.outer.bindName(name)
  189. }
  190. if idx, exists := s.names[name]; exists {
  191. return idx, false
  192. }
  193. idx := uint32(len(s.names))
  194. s.names[name] = idx
  195. return idx, true
  196. }
  197. func (s *scope) bindNameShadow(name string) (uint32, bool) {
  198. if s.lexical {
  199. return s.outer.bindName(name)
  200. }
  201. unique := true
  202. if idx, exists := s.names[name]; exists {
  203. unique = false
  204. // shadow the var
  205. delete(s.names, name)
  206. n := strconv.Itoa(int(idx))
  207. s.names[n] = idx
  208. }
  209. idx := uint32(len(s.names))
  210. s.names[name] = idx
  211. return idx, unique
  212. }
  213. func (c *compiler) markBlockStart() {
  214. c.blockStart = len(c.p.code)
  215. }
  216. func (c *compiler) compile(in *ast.Program) {
  217. c.p.src = NewSrcFile(in.File.Name(), in.File.Source())
  218. if len(in.Body) > 0 {
  219. if !c.scope.strict {
  220. c.scope.strict = c.isStrict(in.Body)
  221. }
  222. }
  223. c.compileDeclList(in.DeclarationList, false)
  224. c.compileFunctions(in.DeclarationList)
  225. if len(in.Body) > 0 {
  226. for _, st := range in.Body[:len(in.Body)-1] {
  227. c.compileStatement(st, false)
  228. }
  229. c.compileStatement(in.Body[len(in.Body)-1], true)
  230. } else {
  231. c.compileStatement(&ast.EmptyStatement{}, true)
  232. }
  233. c.p.code = append(c.p.code, halt)
  234. code := c.p.code
  235. c.p.code = make([]instruction, 0, len(code)+len(c.scope.names)+2)
  236. if c.scope.eval {
  237. if !c.scope.strict {
  238. c.emit(jne(2), newStash)
  239. } else {
  240. c.emit(pop, newStash)
  241. }
  242. }
  243. l := len(c.p.code)
  244. c.p.code = c.p.code[:l+len(c.scope.names)]
  245. for name, nameIdx := range c.scope.names {
  246. c.p.code[l+int(nameIdx)] = bindName(name)
  247. }
  248. c.p.code = append(c.p.code, code...)
  249. for i, _ := range c.p.srcMap {
  250. c.p.srcMap[i].pc += len(c.scope.names)
  251. }
  252. }
  253. func (c *compiler) compileDeclList(v []ast.Declaration, inFunc bool) {
  254. for _, value := range v {
  255. switch value := value.(type) {
  256. case *ast.FunctionDeclaration:
  257. c.compileFunctionDecl(value)
  258. case *ast.VariableDeclaration:
  259. c.compileVarDecl(value, inFunc)
  260. default:
  261. panic(fmt.Errorf("Unsupported declaration: %T", value))
  262. }
  263. }
  264. }
  265. func (c *compiler) compileFunctions(v []ast.Declaration) {
  266. for _, value := range v {
  267. if value, ok := value.(*ast.FunctionDeclaration); ok {
  268. c.compileFunction(value)
  269. }
  270. }
  271. }
  272. func (c *compiler) compileVarDecl(v *ast.VariableDeclaration, inFunc bool) {
  273. for _, item := range v.List {
  274. if c.scope.strict {
  275. c.checkIdentifierLName(item.Name, int(item.Idx)-1)
  276. c.checkIdentifierName(item.Name, int(item.Idx)-1)
  277. }
  278. if !inFunc || item.Name != "arguments" {
  279. idx, ok := c.scope.bindName(item.Name)
  280. _ = idx
  281. //log.Printf("Define var: %s: %x", item.Name, idx)
  282. if !ok {
  283. // TODO: error
  284. }
  285. }
  286. }
  287. }
  288. func (c *compiler) addDecls() []instruction {
  289. code := make([]instruction, len(c.scope.names))
  290. for name, nameIdx := range c.scope.names {
  291. code[nameIdx] = bindName(name)
  292. }
  293. return code
  294. }
  295. func (c *compiler) convertInstrToStashless(instr uint32, args int) (newIdx int, convert bool) {
  296. level := instr >> 24
  297. idx := instr & 0x00FFFFFF
  298. if level > 0 {
  299. level--
  300. newIdx = int((level << 24) | idx)
  301. } else {
  302. iidx := int(idx)
  303. if iidx < args {
  304. newIdx = -iidx - 1
  305. } else {
  306. newIdx = iidx - args + 1
  307. }
  308. convert = true
  309. }
  310. return
  311. }
  312. func (c *compiler) convertFunctionToStashless(code []instruction, args int) {
  313. code[0] = enterFuncStashless{stackSize: uint32(len(c.scope.names) - args), args: uint32(args)}
  314. for pc := 1; pc < len(code); pc++ {
  315. instr := code[pc]
  316. if instr == ret {
  317. code[pc] = retStashless
  318. }
  319. switch instr := instr.(type) {
  320. case getLocal:
  321. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  322. code[pc] = loadStack(newIdx)
  323. } else {
  324. code[pc] = getLocal(newIdx)
  325. }
  326. case setLocal:
  327. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  328. code[pc] = storeStack(newIdx)
  329. } else {
  330. code[pc] = setLocal(newIdx)
  331. }
  332. case setLocalP:
  333. if newIdx, convert := c.convertInstrToStashless(uint32(instr), args); convert {
  334. code[pc] = storeStackP(newIdx)
  335. } else {
  336. code[pc] = setLocalP(newIdx)
  337. }
  338. case getVar:
  339. level := instr.idx >> 24
  340. idx := instr.idx & 0x00FFFFFF
  341. level--
  342. instr.idx = level<<24 | idx
  343. code[pc] = instr
  344. case setVar:
  345. level := instr.idx >> 24
  346. idx := instr.idx & 0x00FFFFFF
  347. level--
  348. instr.idx = level<<24 | idx
  349. code[pc] = instr
  350. }
  351. }
  352. }
  353. func (c *compiler) compileFunctionDecl(v *ast.FunctionDeclaration) {
  354. idx, ok := c.scope.bindName(v.Function.Name.Name)
  355. if !ok {
  356. // TODO: error
  357. }
  358. _ = idx
  359. // log.Printf("Define function: %s: %x", v.Function.Name.Name, idx)
  360. }
  361. func (c *compiler) compileFunction(v *ast.FunctionDeclaration) {
  362. e := &compiledIdentifierExpr{
  363. name: v.Function.Name.Name,
  364. }
  365. e.init(c, v.Function.Idx0())
  366. e.emitSetter(c.compileFunctionLiteral(v.Function, false))
  367. c.emit(pop)
  368. }
  369. func (c *compiler) emit(instructions ...instruction) {
  370. c.p.code = append(c.p.code, instructions...)
  371. }
  372. func (c *compiler) throwSyntaxError(offset int, format string, args ...interface{}) {
  373. panic(&CompilerSyntaxError{
  374. CompilerError: CompilerError{
  375. File: c.p.src,
  376. Offset: offset,
  377. Message: fmt.Sprintf(format, args...),
  378. },
  379. })
  380. }
  381. func (c *compiler) isStrict(list []ast.Statement) bool {
  382. for _, st := range list {
  383. if st, ok := st.(*ast.ExpressionStatement); ok {
  384. if e, ok := st.Expression.(*ast.StringLiteral); ok {
  385. if e.Literal == `"use strict"` || e.Literal == `'use strict'` {
  386. return true
  387. }
  388. } else {
  389. break
  390. }
  391. } else {
  392. break
  393. }
  394. }
  395. return false
  396. }
  397. func (c *compiler) isStrictStatement(s ast.Statement) bool {
  398. if s, ok := s.(*ast.BlockStatement); ok {
  399. return c.isStrict(s.List)
  400. }
  401. return false
  402. }
  403. func (c *compiler) checkIdentifierName(name string, offset int) {
  404. switch name {
  405. case "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield":
  406. c.throwSyntaxError(offset, "Unexpected strict mode reserved word")
  407. }
  408. }
  409. func (c *compiler) checkIdentifierLName(name string, offset int) {
  410. switch name {
  411. case "eval", "arguments":
  412. c.throwSyntaxError(offset, "Assignment to eval or arguments is not allowed in strict mode")
  413. }
  414. }