Skip to content

Commit

Permalink
[Update] Add es6 class support
Browse files Browse the repository at this point in the history
  • Loading branch information
Siubaak committed Jun 23, 2019
1 parent 56c1842 commit 2e1e23a
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 26 deletions.
26 changes: 2 additions & 24 deletions src_/compile/declaration.ts
Expand Up @@ -2,7 +2,7 @@ import * as estree from 'estree'
import State from '../state'
import compile from '../compile'
import { OP } from '../share/const'
import { compileFunc } from './helper'
import { compileFunc, compileCls } from './helper'

export function VariableDeclaration(node: estree.VariableDeclaration, state: State) {
for (let i = 0; i < node.declarations.length; i++) {
Expand All @@ -20,28 +20,6 @@ export function FunctionDeclaration(node: estree.FunctionDeclaration, state: Sta
}

export function ClassDeclaration(node: estree.ClassDeclaration, state: State) {
const clsCode = { op: OP.CLS, val: node.id.name, constructor: false, inherit: false }

const methodBody = node.body.body
for (let i = 0; i < methodBody.length; i++) {
if (methodBody[i].kind === 'constructor') {
compileFunc(methodBody[i].value, state)
clsCode.constructor = true
break
}
}

if (node.superClass) {
compile(node.superClass, state)
clsCode.inherit = true
}

state.opCodes.push(clsCode)
compileCls(node, state)
state.opCodes.push({ op: OP.ALLOC, val: state.symbols.set('var', node.id.name).pointer })
}

export function ClassBody(node: estree.ClassBody, state: State) {
}

export function MethodDefinition(node: estree.MethodDefinition, state: State) {
}
3 changes: 2 additions & 1 deletion src_/compile/expression.ts
Expand Up @@ -2,7 +2,7 @@ import * as estree from 'estree'
import State from '../state'
import compile from '../compile'
import { OP } from '../share/const'
import { compileFunc } from './helper'
import { compileFunc, compileCls } from './helper'

export function ThisExpression(node: estree.ThisExpression, state: State) {
state.opCodes.push({ op: OP.LOADV, val: state.symbols.get('this').pointer })
Expand Down Expand Up @@ -213,6 +213,7 @@ export function TaggedTemplateExpression(node: estree.TaggedTemplateExpression,
}

export function ClassExpression(node: estree.ClassExpression, state: State) {
compileCls(node, state)
}

export function Super(node: estree.Super, state: State) {
Expand Down
35 changes: 35 additions & 0 deletions src_/compile/helper.ts
Expand Up @@ -45,5 +45,40 @@ export function compileFunc(node: FunctionDefinition, state: State) {
type ClassDefinition = estree.ClassDeclaration | estree.ClassExpression

export function compileCls(node: ClassDefinition, state: State) {
const clsCode = { op: OP.CLS, val: node.id.name, constructor: false, inherit: false }

const methodBody = node.body.body
for (let i = 0; i < methodBody.length; i++) {
if (methodBody[i].kind === 'constructor') {
compileFunc(methodBody[i].value, state)
clsCode.constructor = true
break
}
}

if (node.superClass) {
compile(node.superClass, state)
clsCode.inherit = true
}

state.opCodes.push(clsCode)

const methodDefs = node.body.body
for (let i = 0; i < methodDefs.length; i++) {
const met = methodDefs[i]
if (met.kind === 'constructor') continue
// method
compileFunc(met.value, state)
// key
const metKey = met.key
if (metKey.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: metKey.name })
} else if (metKey.type === 'Literal') {
state.opCodes.push({ op: OP.LOADK, val: metKey.value })
} else { // met.computed === true
compile(metKey, state)
}
// definition
state.opCodes.push({ op: OP.CMET, val: met.kind, static: met.static })
}
}
32 changes: 32 additions & 0 deletions src_/jsvm/index.ts
Expand Up @@ -232,6 +232,38 @@ function step(state: State) {
stack.push(ctor)
break
}
case OP.CMET: {
const key = stack.pop()
const met = stack.pop()
const obj = code.static ? stack[stack.length - 1] : stack[stack.length - 1].prototype
switch (code.val) {
case 'get': {
const oriDptor = getDptor(obj, key)
define(obj, key, {
get: met,
set: oriDptor && oriDptor.set,
configurable: true,
})
break
}
case 'set': {
const oriDptor = getDptor(obj, key)
define(obj, key, {
get: oriDptor && oriDptor.get,
set: met,
configurable: true,
})
break
}
default: // kind is 'method'
define(obj, key, {
value: met,
writable: true,
configurable: true,
})
}
break
}
case OP.CALL: {
const func = stack.pop()
const obj = stack.pop()
Expand Down
1 change: 1 addition & 0 deletions src_/share/const.ts
Expand Up @@ -17,6 +17,7 @@ export enum OP {
// (val: class name,
// constructor: has constructor or not,
// inherit: has super class or not)
CMET, // define a method of class (val: kind of methods, static: static methods or not)
FUNC, // declare a function
// (val: function name,
// end: end pc of its op codes,
Expand Down
9 changes: 8 additions & 1 deletion src_/test.ts
Expand Up @@ -6,6 +6,13 @@ class a {
constructor(x) {
this.x = x
}
static k() {
console.log('a')
}
b() {
console.log(this.x)
}
}
console.log(new a(2))
const j = new a(2)
console.log(a.k)
`)

0 comments on commit 2e1e23a

Please sign in to comment.