Skip to content

Commit

Permalink
perf: 系统性地改 [] notation 为 . notation
Browse files Browse the repository at this point in the history
  • Loading branch information
harttle committed Dec 15, 2020
1 parent 481e9dc commit 2fed822
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 37 deletions.
2 changes: 2 additions & 0 deletions src/ast/syntax-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export function I (name: string) {

export const NULL = new Null()

export const CTX_DATA = BINARY(I('ctx'), '.', I('data'))

export function BINARY (lhs: Expression, op: BinaryOperator, rhs: Expression) {
return new BinaryExpression(lhs, op, rhs)
}
Expand Down
14 changes: 6 additions & 8 deletions src/compilers/anode-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getANodePropByName } from '../ast/san-ast-util'
import * as TypeGuards from '../ast/san-type-guards'
import { IDGenerator } from '../utils/id-generator'
import { JSONStringify, RegexpReplace, Statement, FunctionDefinition, ElseIf, Else, MapAssign, Foreach, If, MapLiteral, ComponentRendererReference, FunctionCall, Expression } from '../ast/syntax-node'
import { createUtilCall, createHTMLExpressionAppend, createHTMLLiteralAppend, L, I, ASSIGN, STATMENT, UNARY, DEF, BINARY, RETURN } from '../ast/syntax-util'
import { CTX_DATA, createUtilCall, createHTMLExpressionAppend, createHTMLLiteralAppend, L, I, ASSIGN, STATMENT, UNARY, DEF, BINARY, RETURN } from '../ast/syntax-util'
import { sanExpr } from '../compilers/san-expr-compiler'

/**
Expand Down Expand Up @@ -112,13 +112,12 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
const { item, index, value } = aNode.directives.for
const key = I(id.next('key'))
const val = I(id.next('val'))
const data = BINARY(I('ctx'), '.', I('data'))
const list = id.next('list')

yield DEF(list, sanExpr(value))
yield new Foreach(key, val, I(list), [
...index ? [ASSIGN(BINARY(data, '[]', L(index)), key)] : [],
ASSIGN(BINARY(data, '.', I(item!)), val),
...index ? [ASSIGN(BINARY(CTX_DATA, '[]', L(index)), key)] : [],
ASSIGN(BINARY(CTX_DATA, '.', I(item!)), val),
...this.compile(forElementANode, false)
])
}
Expand Down Expand Up @@ -228,14 +227,13 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
if (content.length) {
body.push(DEF('html', L('')))

const ctxData = BINARY(I('ctx'), '.', I('data'))
const compData = this.id.next('compData')
body.push(DEF(compData, ctxData))
body.push(ASSIGN(ctxData, new MapAssign(new MapLiteral(), [ctxData, I('data')])))
body.push(DEF(compData, CTX_DATA))
body.push(ASSIGN(CTX_DATA, new MapAssign(new MapLiteral(), [CTX_DATA, I('data')])))

for (const child of content) body.push(...this.compile(child, false))

body.push(ASSIGN(ctxData, I(compData)))
body.push(ASSIGN(CTX_DATA, I(compData)))
body.push(RETURN(I('html')))
} else {
body.push(RETURN(L('')))
Expand Down
14 changes: 7 additions & 7 deletions src/compilers/element-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ANodeCompiler } from './anode-compiler'
import { ExprNode, ANodeProperty, Directive, ANode } from 'san'
import { isExprNumberNode, isExprStringNode, isExprBoolNode } from '../ast/san-type-guards'
import { createUtilCall, createIfStrictEqual, createIfNotNull, createDefaultValue, createHTMLLiteralAppend, createHTMLExpressionAppend, NULL, L, I, ASSIGN, DEF } from '../ast/syntax-util'
import { ArrayIncludes, Else, Foreach, If } from '../ast/syntax-node'
import { FilterCall, ArrayIncludes, Else, Foreach, If } from '../ast/syntax-node'
import { sanExpr } from './san-expr-compiler'

const BOOL_ATTRIBUTES = ['readonly', 'disabled', 'multiple', 'checked']
Expand Down Expand Up @@ -77,11 +77,11 @@ export class ElementCompiler {

if (prop.name === 'readonly' || prop.name === 'disabled' || prop.name === 'multiple') {
if (this.isLiteral(prop.expr)) {
if (_.boolAttrFilter(prop.name, prop.expr.value)) {
if (_._boolAttrFilter(prop.name, prop.expr.value)) {
yield createHTMLLiteralAppend(` ${prop.name}`)
}
} else {
yield createHTMLExpressionAppend(createUtilCall('boolAttrFilter', [L(prop.name), sanExpr(prop.expr)]))
yield createHTMLExpressionAppend(new FilterCall('_boolAttr', [L(prop.name), sanExpr(prop.expr)]))
}
return
}
Expand All @@ -102,9 +102,9 @@ export class ElementCompiler {
}
}
if (this.isLiteral(prop.expr)) {
yield createHTMLLiteralAppend(_.attrFilter(prop.name, prop.expr.value, true))
yield createHTMLLiteralAppend(_._attrFilter(prop.name, prop.expr.value, true))
} else {
yield createHTMLExpressionAppend(createUtilCall('attrFilter', [L(prop.name), sanExpr(prop.expr), L(true)]))
yield createHTMLExpressionAppend(new FilterCall('_attr', [L(prop.name), sanExpr(prop.expr), L(true)]))
}
}

Expand All @@ -121,10 +121,10 @@ export class ElementCompiler {
const iterable = I(bindProps)
yield new Foreach(key, value, iterable, [
new If(new ArrayIncludes(L(BOOL_ATTRIBUTES), key), [
createHTMLExpressionAppend(createUtilCall('boolAttrFilter', [key, value]))
createHTMLExpressionAppend(createUtilCall('_boolAttrFilter', [key, value]))
]),
new Else([
createHTMLExpressionAppend(createUtilCall('attrFilter', [key, value, L(true)]))
createHTMLExpressionAppend(new FilterCall('_attr', [key, value, L(true)]))
])
])
}
Expand Down
19 changes: 5 additions & 14 deletions src/compilers/san-expr-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
* 编译源码的 helper 方法集合
*/
import { ExprStringNode, ExprNode, ExprTertiaryNode, ExprBinaryNode, ExprUnaryNode, ExprInterpNode, ExprAccessorNode, ExprCallNode, ExprTextNode, ExprObjectNode, ExprArrayNode } from 'san'
import { isValidIdentifier } from '../utils/lang'
import * as TypeGuards from '../ast/san-type-guards'
import { _ } from '../runtime/underscore'
import { MapLiteral, ArrayLiteral, FilterCall, FunctionCall, Literal, Identifier, ConditionalExpression, BinaryExpression, UnaryExpression, Expression } from '../ast/syntax-node'
import { L, NULL, createUtilCall } from '../ast/syntax-util'
import { CTX_DATA, L, NULL, createUtilCall } from '../ast/syntax-util'

// 输出为 HTML 并转义、输出为 HTML 不转义、非输出表达式
export type OutputType = 'html' | 'rawhtml' | 'expr'
Expand Down Expand Up @@ -46,14 +45,10 @@ function tertiary (e: ExprTertiaryNode) {

// 生成数据访问表达式代码
export function dataAccess (accessorExpr: ExprAccessorNode | undefined, outputType: OutputType) {
let data = new BinaryExpression(new Identifier('ctx'), '.', new Identifier('data'))
if (!accessorExpr) return data
if (!accessorExpr) return CTX_DATA
let data = CTX_DATA
for (const path of accessorExpr.paths) {
if (TypeGuards.isExprStringNode(path) && isValidIdentifier(path.value)) {
data = new BinaryExpression(data, '.', new Identifier(path.value))
} else {
data = new BinaryExpression(data, '[]', sanExpr(path))
}
data = new BinaryExpression(data, '[]', sanExpr(path))
}
return outputCode(data, outputType)
}
Expand All @@ -63,11 +58,7 @@ function callExpr (callExpr: ExprCallNode, outputType: OutputType) {
const paths = callExpr.name.paths
let fn = new BinaryExpression(new Identifier('ctx'), '.', new Identifier('instance'))
for (const path of paths) {
if (TypeGuards.isExprStringNode(path) && isValidIdentifier(path.value)) {
fn = new BinaryExpression(fn, '.', new Identifier(path.value))
} else {
fn = new BinaryExpression(fn, '[]', sanExpr(path))
}
fn = new BinaryExpression(fn, '[]', sanExpr(path))
}
return outputCode(new FunctionCall(fn, callExpr.args.map(arg => sanExpr(arg))), outputType)
}
Expand Down
17 changes: 17 additions & 0 deletions src/optimizers/bracket-to-dot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BinaryExpression, Expression, Statement } from '../ast/syntax-node'
import { isLiteral, I, isBinaryExpression } from '../ast/syntax-util'
import { walk } from '../ast/syntax-tree-walker'
import { isValidIdentifier } from '../utils/lang'

export function bracketToDot (node: Expression | Statement) {
for (const expr of walk(node)) {
if (isBracketNotation(expr) && isLiteral(expr.rhs) && isValidIdentifier(expr.rhs.value)) {
expr.op = '.'
expr.rhs = I(expr.rhs.value)
}
}
}

function isBracketNotation (expr: Expression | Statement): expr is BinaryExpression {
return isBinaryExpression(expr) && expr.op === '[]'
}
15 changes: 12 additions & 3 deletions src/runtime/underscore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const BASE_PROPS = {

export interface Context {
parentCtx?: Context;
instance: any
}

const HTML_ENTITY = {
Expand Down Expand Up @@ -81,7 +82,7 @@ function _xstyleFilter (inherits: object | string, own: string) {
return own
}

function attrFilter (name: string, value: string, needHTMLEscape: boolean) {
function _attrFilter (name: string, value: string, needHTMLEscape: boolean) {
if (value) {
return ' ' + name + '="' + (needHTMLEscape ? escapeHTML(value) : value) + '"'
}
Expand All @@ -91,10 +92,18 @@ function attrFilter (name: string, value: string, needHTMLEscape: boolean) {
return ''
}

function boolAttrFilter (name: string, value: string) {
function _boolAttrFilter (name: string, value: string) {
return value ? ' ' + name : ''
}

function callFilter (ctx: Context, name: string, ...args: any[]) {
return ctx.instance.filters[name].call(ctx.instance, ...args)
}

function callComputed (ctx: Context, name: string) {
return ctx.instance.computed[name].apply(ctx.instance)
}

function iterate (val: any[] | object) {
return isArray(val) ? val.entries() : Object.entries(val)
}
Expand Down Expand Up @@ -126,5 +135,5 @@ function getRootCtx<T extends {parentCtx?: T}> (ctx: T) {
}

export const _ = {
output, createInstanceFromClass, escapeHTML, boolAttrFilter, attrFilter, _classFilter, _styleFilter, _xstyleFilter, _xclassFilter, createFromPrototype, getRootCtx, iterate
output, createInstanceFromClass, escapeHTML, _boolAttrFilter, _attrFilter, _classFilter, _styleFilter, _xstyleFilter, _xclassFilter, createFromPrototype, getRootCtx, iterate, callFilter, callComputed
}
11 changes: 9 additions & 2 deletions src/target-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Compiler } from '../models/compiler'
import { tsSourceFile2js } from '../compilers/ts2js'
import { RenderOptions } from '../compilers/renderer-options'
import { CompileOptions } from './compilers/compile-options'
import { FunctionDefinition } from '../ast/syntax-node'
import { bracketToDot } from '../optimizers/bracket-to-dot'

const debug = debugFactory('target-js')

Expand Down Expand Up @@ -54,7 +56,7 @@ export default class ToJSCompiler implements Compiler {

for (const info of componentInfos) {
const emitter = new JSEmitter()
emitter.writeFunctionDefinition(info.compileToRenderer(options))
emitter.writeFunctionDefinition(this.optimize(info.compileToRenderer(options)))

const rawRendererText = emitter.fullText()
const resolvedRenderer = this.createRenderer(rawRendererText, { sanSSRHelpers, sanSSRResolver })
Expand Down Expand Up @@ -96,7 +98,7 @@ export default class ToJSCompiler implements Compiler {
// 编译 render 函数
for (const info of sourceFile.componentInfos) {
emitter.nextLine(`sanSSRResolver.setRenderer("${info.id}", `)
emitter.writeFunctionDefinition(info.compileToRenderer(options))
emitter.writeFunctionDefinition(this.optimize(info.compileToRenderer(options)))
emitter.feedLine(');')
}

Expand Down Expand Up @@ -144,4 +146,9 @@ export default class ToJSCompiler implements Compiler {
emitter.feedLine(');')
}
}

private optimize (root: FunctionDefinition) {
bracketToDot(root)
return root
}
}
6 changes: 3 additions & 3 deletions src/target-js/js-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,14 @@ export class JSEmitter extends Emitter {
}

private writeComputedCall (node: ComputedCall) {
this.write(`ctx.instance.computed["${node.name}"].apply(ctx.instance)`)
this.write(`_.callComputed(ctx, "${node.name}")`)
}

private writeFilterCall (node: FilterCall) {
if (['_style', '_class', '_xstyle', '_xclass'].includes(node.name)) {
if (['_style', '_class', '_xstyle', '_xclass', '_attr', '_boolAttr'].includes(node.name)) {
this.write(`_.${node.name}Filter(`)
} else {
this.write(`ctx.instance.filters["${node.name}"].call(ctx.instance, `)
this.write(`_.callFilter(ctx, "${node.name}", `)
}
this.writeExpressionList(node.args)
this.write(')')
Expand Down

0 comments on commit 2fed822

Please sign in to comment.