Skip to content

Commit

Permalink
[Update] Add rest element of object & array
Browse files Browse the repository at this point in the history
  • Loading branch information
Siubaak committed Jul 24, 2019
1 parent 8aae1f2 commit c0751a1
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 49 deletions.
41 changes: 30 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 45 additions & 33 deletions src_/compile/pattern.ts
Expand Up @@ -7,8 +7,9 @@ import { compilePattern } from './helper';
export function ObjectPattern(node: estree.ObjectPattern, state: State) {
for (let i = 0; i < node.properties.length; i++) {
const property = node.properties[i]
let value: estree.Pattern = (property as estree.AssignmentProperty).value
state.opCodes.push({ op: OP.COPY })
if (property.type === 'Property') {
state.opCodes.push({ op: OP.COPY })
// key
const propKey = property.key
if (propKey.type === 'Identifier') {
Expand All @@ -17,28 +18,35 @@ export function ObjectPattern(node: estree.ObjectPattern, state: State) {
compile(propKey, state)
}
state.opCodes.push({ op: OP.MGET })
// value
const value = property.value
if (value.type === 'Identifier') {
if (state.symbols.type) {
state.opCodes.push({ op: OP.ALLOC, val: state.symbols.set(value.name).pointer })
} else { // property.type === 'RestElement'
for (let j = 0; j < i; j++) {
const propKey = node.properties[j].key
if (propKey.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: propKey.name })
} else {
state.opCodes.push({ op: OP.STORE, val: state.symbols.get(value.name).pointer })
compile(propKey, state)
}
} else if (value.type === 'MemberExpression') {
compile(value.object, state)
const property = value.property
if (property.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: property.name })
} else { // node.computed === true
compile(property, state)
}
state.opCodes.push({ op: OP.MSET })
}
state.opCodes.push({ op: OP.REST, val: i, type: 'obj' })
value = (property as any).argument
}
if (value.type === 'Identifier') {
if (state.symbols.type) {
state.opCodes.push({ op: OP.ALLOC, val: state.symbols.set(value.name).pointer })
} else {
compilePattern(value, state)
state.opCodes.push({ op: OP.STORE, val: state.symbols.get(value.name).pointer })
}
} else { // property.type === 'RestElement'

} else if (value.type === 'MemberExpression') {
compile(value.object, state)
const prop = value.property
if (prop.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: prop.name })
} else { // node.computed === true
compile(prop, state)
}
state.opCodes.push({ op: OP.MSET })
} else {
compilePattern(value, state)
}
}
state.opCodes.push({ op: OP.POP })
Expand All @@ -48,28 +56,32 @@ export function ArrayPattern(node: estree.ArrayPattern, state: State) {
for (let i = 0; i < node.elements.length; i++) {
const element = node.elements[i]
if (!element) continue // for the case: let [ , x] = [1, 2]
let value: estree.Pattern = element
state.opCodes.push({ op: OP.COPY })
state.opCodes.push({ op: OP.LOADK, val: i })
state.opCodes.push({ op: OP.MGET })
if (element.type === 'Identifier') {
if (element.type === 'RestElement') {
state.opCodes.push({ op: OP.REST, val: i, type: 'arr' })
value = element.argument
} else {
state.opCodes.push({ op: OP.LOADK, val: i })
state.opCodes.push({ op: OP.MGET })
}
if (value.type === 'Identifier') {
if (state.symbols.type) {
state.opCodes.push({ op: OP.ALLOC, val: state.symbols.set(element.name).pointer })
state.opCodes.push({ op: OP.ALLOC, val: state.symbols.set(value.name).pointer })
} else {
state.opCodes.push({ op: OP.STORE, val: state.symbols.get(element.name).pointer })
state.opCodes.push({ op: OP.STORE, val: state.symbols.get(value.name).pointer })
}
} else if (element.type === 'MemberExpression') {
compile(element.object, state)
const property = element.property
if (property.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: property.name })
} else if (value.type === 'MemberExpression') {
compile(value.object, state)
const prop = value.property
if (prop.type === 'Identifier') {
state.opCodes.push({ op: OP.LOADK, val: prop.name })
} else { // node.computed === true
compile(property, state)
compile(prop, state)
}
state.opCodes.push({ op: OP.MSET })
} else if (element.type === 'RestElement') {

} else {
compilePattern(element, state)
compilePattern(value, state)
}
}
state.opCodes.push({ op: OP.POP })
Expand Down
15 changes: 15 additions & 0 deletions src_/jsvm/index.ts
Expand Up @@ -129,6 +129,21 @@ function step(state: State) {
object[key] = value
break
}
case OP.REST: {
if (code.type === 'obj') {
const rmKeys = stack.splice(stack.length - code.val)
const object = Object.assign({}, stack.pop())
for (let i = 0; i < rmKeys.length; i++) {
delete object[rmKeys[i]]
}
stack.push(object)
} else if (code.type === 'arr') {
stack.push(stack.pop().slice(code.val))
} else { // code.type === 'func'

}
break
}
case OP.KOVS: {
const kovs = []
if (code.val) {
Expand Down
6 changes: 5 additions & 1 deletion src_/share/const.ts
Expand Up @@ -13,7 +13,9 @@ export enum OP {
OBJ, // create object (val: array of property kinds)
MGET, // get member of object (no val)
MSET, // set member of object (no val)
DEL, // delete property ()
REST, // get rest elements of object, array & function params
// (val: number of removed elements,
// type: 'obj' | 'arr' | 'func')
KOVS, // get enumerable properties or iterable values of an object for for-in or for-of statement
// (val: true for keys and false for values)
CLS, // declare a class
Expand All @@ -30,9 +32,11 @@ export enum OP {
// length: function.length)
CALL, // invoke functions or methods
// (val: number of parameters,
// spread: array of spread element indexes,
// catch: { pc: catch statement pc })
NEW, // create an object by constructor
// (val: number of parameters,
// spread: array of spread element indexes,
// catch: { pc: catch statement pc })
BRK, // break (val: label)
CONTI, // continue (val: label)
Expand Down
2 changes: 1 addition & 1 deletion src_/state/index.ts
@@ -1,5 +1,5 @@
import { OpCode } from '../share/const'
import SymbolTable, { VarType } from './symbols'
import SymbolTable from './symbols'

export default class State {
readonly stack: any[] = []
Expand Down
2 changes: 1 addition & 1 deletion src_/state/symbols.ts
@@ -1,6 +1,6 @@
import { hasOwn } from '../share/utils'

export type VarType = 'var' | 'let' | 'const'
type VarType = 'var' | 'let' | 'const'

interface VarSymbol {
type: VarType
Expand Down
4 changes: 2 additions & 2 deletions src_/test.ts
Expand Up @@ -2,6 +2,6 @@ import Sval from '.'

const interpreter = new Sval()
interpreter.run(`
const { a = 1, b } = { b: 2 }
console.log(a, b)
const [a, ...g] = [1]
console.log(a, g)
`)

0 comments on commit c0751a1

Please sign in to comment.