Skip to content

Commit

Permalink
refactor: compatible with san-ssr-target-php
Browse files Browse the repository at this point in the history
  • Loading branch information
liuyue28 committed Jan 6, 2021
1 parent 24f514b commit f8e8b92
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/ast/renderer-ast-factory.ts
@@ -1,11 +1,11 @@
import { MapLiteral, UnaryOperator, UnaryExpression, NewExpression, VariableDefinition, ReturnStatement, BinaryOperator, If, Null, AssignmentStatement, Statement, Expression, Identifier, ExpressionStatement, BinaryExpression, Literal } from './renderer-ast-node'

export function createHTMLLiteralAppend (html: string) {
return STATMENT(BINARY(I('html'), '+=', L(html)))
return STATEMENT(BINARY(I('html'), '+=', L(html)))
}

export function createHTMLExpressionAppend (expr: Expression) {
return STATMENT(BINARY(I('html'), '+=', expr))
return STATEMENT(BINARY(I('html'), '+=', expr))
}

export function createDefaultValue (expr: Expression, value: Expression): Statement {
Expand Down Expand Up @@ -52,7 +52,7 @@ export function RETURN (val: Expression) {
return new ReturnStatement(val)
}

export function STATMENT (expr: Expression) {
export function STATEMENT (expr: Expression) {
return new ExpressionStatement(expr)
}

Expand Down
39 changes: 37 additions & 2 deletions src/ast/renderer-ast-node.ts
@@ -1,4 +1,5 @@
import { ComponentInfo } from '../models/component-info'
import type { ComponentReference } from '../models/component-reference'

/**
* SSR 输出代码的 AST 节点
Expand Down Expand Up @@ -49,9 +50,12 @@ export enum SyntaxKind {
RegexpReplace = 28,
JSONStringify = 29,
HelperCall = 30,
GetRootCtxCall = 31,
ComponentReferenceLiteral = 32,
SlotRendererDefinition = 33,
}

export type Expression = Identifier | FunctionDefinition | Literal | BinaryExpression | UnaryExpression | CreateComponentInstance | NewExpression | MapLiteral | ComponentRendererReference | FunctionCall | Null | MapAssign | ArrayIncludes | ConditionalExpression | FilterCall | HelperCall | EncodeURIComponent | ArrayLiteral | RegexpReplace | JSONStringify | ComputedCall
export type Expression = Identifier | FunctionDefinition | Literal | BinaryExpression | UnaryExpression | CreateComponentInstance | NewExpression | MapLiteral | ComponentRendererReference | FunctionCall | Null | MapAssign | ArrayIncludes | ConditionalExpression | FilterCall | HelperCall | EncodeURIComponent | ArrayLiteral | RegexpReplace | JSONStringify | ComputedCall | GetRootCtxCall | ComponentReferenceLiteral | SlotRendererDefinition

export type Statement = ReturnStatement | ImportHelper | VariableDefinition | AssignmentStatement | If | ElseIf | Else | Foreach | ExpressionStatement

Expand Down Expand Up @@ -88,6 +92,21 @@ export class ComponentRendererReference implements SyntaxNode {
) {}
}

export class ComponentReferenceLiteral implements SyntaxNode {
public readonly kind = SyntaxKind.ComponentReferenceLiteral
constructor (
public value: ComponentReference
) {}

public toMapLiteral () {
const { specifier, id } = this.value
return new MapLiteral([
[Identifier.create('specifier'), Literal.create(specifier)],
[Identifier.create('id'), Literal.create(id)]
])
}
}

export class Null implements SyntaxNode {
public readonly kind = SyntaxKind.Null
private static instance = new Null()
Expand Down Expand Up @@ -225,10 +244,17 @@ export class FilterCall implements SyntaxNode {
) {}
}

export class GetRootCtxCall implements SyntaxNode {
public readonly kind = SyntaxKind.GetRootCtxCall
constructor (
public args: Expression[]
) {}
}

export class HelperCall implements SyntaxNode {
public readonly kind = SyntaxKind.HelperCall
constructor (
public name: 'styleFilter' | 'classFilter' | 'xstyleFilter' | 'xclassFilter' | 'attrFilter' | 'boolAttrFilter' | 'output' | 'getRootCtx',
public name: 'styleFilter' | 'classFilter' | 'xstyleFilter' | 'xclassFilter' | 'attrFilter' | 'boolAttrFilter' | 'output',
public args: Expression[]
) {}
}
Expand Down Expand Up @@ -297,6 +323,15 @@ export class FunctionDefinition implements SyntaxNode {
) {}
}

export class SlotRendererDefinition implements SyntaxNode {
public readonly kind = SyntaxKind.SlotRendererDefinition
constructor (
public name: string,
public args: VariableDefinition[],
public body: Iterable<Statement>
) {}
}

export class Literal implements SyntaxNode {
public readonly kind = SyntaxKind.Literal
private static cache: Map<string, Literal> = new Map()
Expand Down
2 changes: 1 addition & 1 deletion src/ast/renderer-ast-util.ts
@@ -1,7 +1,7 @@
import { SyntaxKind, SyntaxNode, Block, Identifier, ExpressionStatement, BinaryExpression, Literal } from './renderer-ast-node'

export function isBlock (node: any): node is Block {
const blocks = [SyntaxKind.If, SyntaxKind.ElseIf, SyntaxKind.Else, SyntaxKind.Foreach, SyntaxKind.FunctionDefinition]
const blocks = [SyntaxKind.If, SyntaxKind.ElseIf, SyntaxKind.Else, SyntaxKind.Foreach, SyntaxKind.FunctionDefinition, SyntaxKind.SlotRendererDefinition]
return isSyntaxNode(node) && blocks.includes(node.kind)
}

Expand Down
3 changes: 3 additions & 0 deletions src/ast/renderer-ast-walker.ts
Expand Up @@ -18,6 +18,7 @@ export function * walk (node: Expression | Statement): Iterable<Expression | Sta
case SyntaxKind.Null:
case SyntaxKind.ImportHelper:
case SyntaxKind.ComputedCall:
case SyntaxKind.ComponentReferenceLiteral:
break
case SyntaxKind.ArrayIncludes:
yield * walk(node.arr)
Expand All @@ -37,10 +38,12 @@ export function * walk (node: Expression | Statement): Iterable<Expression | Sta
yield * walk(node.trueValue)
break
case SyntaxKind.FilterCall:
case SyntaxKind.GetRootCtxCall:
case SyntaxKind.HelperCall:
for (const arg of node.args) yield * walk(arg)
break
case SyntaxKind.FunctionDefinition:
case SyntaxKind.SlotRendererDefinition:
for (const arg of node.args) yield * walk(arg)
for (const stmt of node.body) yield * walk(stmt)
break
Expand Down
18 changes: 9 additions & 9 deletions src/compilers/anode-compiler.ts
Expand Up @@ -6,8 +6,8 @@ import { ElementCompiler } from './element-compiler'
import { getANodePropByName } from '../ast/san-ast-util'
import * as TypeGuards from '../ast/san-type-guards'
import { IDGenerator } from '../utils/id-generator'
import { HelperCall, JSONStringify, RegexpReplace, Statement, FunctionDefinition, ElseIf, Else, MapAssign, Foreach, If, MapLiteral, ComponentRendererReference, FunctionCall, Expression } from '../ast/renderer-ast-node'
import { CTX_DATA, EMPTY_MAP, createHTMLExpressionAppend, createHTMLLiteralAppend, L, I, ASSIGN, STATMENT, UNARY, DEF, BINARY, RETURN } from '../ast/renderer-ast-factory'
import { JSONStringify, RegexpReplace, Statement, SlotRendererDefinition, ElseIf, Else, MapAssign, Foreach, If, MapLiteral, ComponentRendererReference, FunctionCall, Expression, GetRootCtxCall, ComponentReferenceLiteral } from '../ast/renderer-ast-node'
import { CTX_DATA, createHTMLExpressionAppend, createHTMLLiteralAppend, L, I, ASSIGN, STATEMENT, UNARY, DEF, BINARY, RETURN } from '../ast/renderer-ast-factory'
import { sanExpr } from '../compilers/san-expr-compiler'

/**
Expand Down Expand Up @@ -53,7 +53,7 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
return BINARY(refs, '[]', sanExpr(aNode.directives.is.value))
}
if (this.componentInfo.childComponents.has(aNode.tagName)) {
return this.componentInfo.childComponents.get(aNode.tagName)!.toAST()
return new ComponentReferenceLiteral(this.componentInfo.childComponents.get(aNode.tagName)!)
}
}

Expand Down Expand Up @@ -117,7 +117,7 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
yield DEF(list, sanExpr(value))
yield new Foreach(key, val, I(list), [
...index ? [ASSIGN(BINARY(CTX_DATA, '[]', L(index)), key)] : [],
ASSIGN(BINARY(CTX_DATA, '.', I(item!)), val),
ASSIGN(BINARY(CTX_DATA, '[]', L(item!)), val),
...this.compile(forElementANode, false)
])
}
Expand All @@ -132,12 +132,12 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
const slotData = I(id.next('slotData'))
yield DEF(slotData.name, new MapLiteral([]))
if (aNode.directives.bind) {
yield STATMENT(new MapAssign(slotData, [sanExpr(aNode.directives.bind.value)]))
yield STATEMENT(new MapAssign(slotData, [sanExpr(aNode.directives.bind.value)]))
}

const props = aNode.vars || []
if (props.length) {
yield STATMENT(new MapAssign(
yield STATEMENT(new MapAssign(
slotData,
[new MapLiteral(props.map(prop => [L(prop.name), sanExpr(prop.expr)]))]
))
Expand Down Expand Up @@ -169,7 +169,7 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
}

private createDataComment () {
const dataExpr = BINARY(new HelperCall('getRootCtx', [I('ctx')]), '.', I('data'))
const dataExpr = BINARY(new GetRootCtxCall([I('ctx')]), '.', I('data'))
return [
createHTMLLiteralAppend('<!--s-data:'),
createHTMLExpressionAppend(new RegexpReplace(new JSONStringify(dataExpr), '(?<=-)-', L('\\-'))),
Expand Down Expand Up @@ -229,7 +229,7 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {

const compData = this.id.next('compData')
body.push(DEF(compData, CTX_DATA))
body.push(ASSIGN(CTX_DATA, new MapAssign(EMPTY_MAP, [CTX_DATA, I('data')])))
body.push(STATEMENT(new MapAssign(CTX_DATA, [I('data')])))

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

Expand All @@ -238,7 +238,7 @@ export class ANodeCompiler<T extends 'none' | 'typed'> {
} else {
body.push(RETURN(L('')))
}
return new FunctionDefinition('', args, body)
return new SlotRendererDefinition('', args, body)
}

private childRenderData (aNode: ANode) {
Expand Down
14 changes: 7 additions & 7 deletions src/compilers/renderer-compiler.ts
@@ -1,8 +1,8 @@
import { ANodeCompiler } from './anode-compiler'
import { ComponentInfo } from '../models/component-info'
import { RenderOptions } from './renderer-options'
import { FunctionDefinition, ComputedCall, Foreach, FunctionCall, MapLiteral, If, CreateComponentInstance, ImportHelper } from '../ast/renderer-ast-node'
import { EMPTY_MAP, STATMENT, NEW, BINARY, ASSIGN, DEF, RETURN, createDefaultValue, L, I } from '../ast/renderer-ast-factory'
import { FunctionDefinition, ComputedCall, Foreach, FunctionCall, MapLiteral, If, CreateComponentInstance, ImportHelper, ComponentReferenceLiteral } from '../ast/renderer-ast-node'
import { EMPTY_MAP, STATEMENT, NEW, BINARY, ASSIGN, DEF, RETURN, createDefaultValue, L, I, NULL } from '../ast/renderer-ast-factory'
import { IDGenerator } from '../utils/id-generator'
import { mergeLiteralAdd } from '../optimizers/merge-literal-add'

Expand All @@ -20,7 +20,7 @@ export class RendererCompiler {
* 把 ComponentInfo 编译成函数源码,返回 Renderer 函数的 AST
*/
public compileToRenderer (componentInfo: ComponentInfo) {
const args = [DEF('data'), DEF('noDataOutput'), DEF('parentCtx'), DEF('tagName', L('div')), DEF('slots')]
const args = [DEF('data'), DEF('noDataOutput', L(false)), DEF('parentCtx', NULL), DEF('tagName', L('div')), DEF('slots', EMPTY_MAP)]
const fn = new FunctionDefinition(this.options.functionName || '', args,
this.compileComponentRendererBody(componentInfo)
)
Expand Down Expand Up @@ -49,8 +49,8 @@ export class RendererCompiler {

// call inited
if (info.hasMethod('inited')) {
body.push(STATMENT(new FunctionCall(
BINARY(BINARY(I('ctx'), '.', I('instance')), '.', I('inited')),
body.push(STATEMENT(new FunctionCall(
BINARY(I('instance'), '.', I('inited')),
[]
)))
}
Expand All @@ -71,7 +71,7 @@ export class RendererCompiler {

private compileContext (info: ComponentInfo) {
const refs = info.hasDynamicComponent()
? new MapLiteral([...info.childComponents.entries()].map(([key, val]) => [L(key), val.toAST()]))
? new MapLiteral([...info.childComponents.entries()].map(([key, val]) => [L(key), new ComponentReferenceLiteral(val)]))
: EMPTY_MAP
return [
DEF('instance', new CreateComponentInstance(info)),
Expand Down Expand Up @@ -100,7 +100,7 @@ export class RendererCompiler {
}

private emitInitDataInRuntime () {
const item = BINARY(I('data'), '[]', I('key'))
const item = BINARY(BINARY(I('ctx'), '.', I('data')), '[]', I('key'))

return [
ASSIGN(
Expand Down
1 change: 1 addition & 0 deletions src/compilers/san-expr-compiler.ts
Expand Up @@ -56,6 +56,7 @@ export function dataAccess (accessorExpr: ExprAccessorNode, outputType: OutputTy
function callExpr (callExpr: ExprCallNode, outputType: OutputType) {
const paths = callExpr.name.paths
let fn = new BinaryExpression(I('ctx'), '.', I('instance'))
fn = new BinaryExpression(fn, '.', I(paths.shift()!.value))
for (const path of paths) {
fn = new BinaryExpression(fn, '[]', sanExpr(path))
}
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Expand Up @@ -12,6 +12,9 @@ export { getANodePropByName } from './ast/san-ast-util'
export { Emitter } from './utils/emitter'
export { TypeGuards }
export { _ } from './runtime/underscore'
export { SyntaxKind } from './ast/renderer-ast-node'
export type { Expression, Statement, FunctionDefinition, VariableDefinition, Literal, MapLiteral, ArrayLiteral, UnaryExpression, Foreach, BinaryExpression, SlotRendererDefinition } from './ast/renderer-ast-node'
export { assertNever } from './utils/lang'

// class types
export { SanSourceFile, TypedSanSourceFile, DynamicSanSourceFile, isTypedSanSourceFile } from './models/san-source-file'
Expand All @@ -21,6 +24,7 @@ export { ComponentInfo, TypedComponentInfo, DynamicComponentInfo } from './model
export { ComponentReference } from './models/component-reference'
export { COMPONENT_RESERVED_MEMBERS } from './models/component'
export { CompileInput } from './models/options'
export { RenderOptions } from './compilers/renderer-options'

let defaultProject: SanProject

Expand Down
10 changes: 0 additions & 10 deletions src/models/component-reference.ts
@@ -1,6 +1,4 @@
import { ComponentConstructor } from 'san'
import { L, I } from '../ast/renderer-ast-factory'
import { MapLiteral } from '../ast/renderer-ast-node'

/**
* 表示一个组件的引用,被引用组件可能在当前文件,也可能在外部文件。例如:
Expand All @@ -26,14 +24,6 @@ export class ComponentReference {
*/
public readonly id: string
) {}

toAST () {
const { specifier, id } = this
return new MapLiteral([
[I('specifier'), L(specifier)],
[I('id'), L(id)]
])
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/target-js/index.ts
Expand Up @@ -12,7 +12,7 @@ import { CompileOptions } from './compilers/compile-options'
import { FunctionDefinition } from '../ast/renderer-ast-node'
import { bracketToDot } from '../optimizers/bracket-to-dot'

const debug = debugFactory('target-js')
const debug = debugFactory('san-ssr:target-js')

export default class ToJSCompiler implements Compiler {
constructor (private project: SanProject) {}
Expand Down
13 changes: 11 additions & 2 deletions src/target-js/js-emitter.ts
@@ -1,4 +1,4 @@
import { Literal, Foreach, FunctionDefinition, ArrayLiteral, UnaryExpression, MapLiteral, Statement, SyntaxKind, Expression, VariableDefinition } from '../ast/renderer-ast-node'
import { Literal, Foreach, FunctionDefinition, ArrayLiteral, UnaryExpression, MapLiteral, Statement, SyntaxKind, Expression, VariableDefinition, SlotRendererDefinition } from '../ast/renderer-ast-node'
import { Emitter } from '../utils/emitter'
import { assertNever } from '../utils/lang'

Expand Down Expand Up @@ -78,12 +78,18 @@ export class JSEmitter extends Emitter {
this.writeExpressionList(node.args)
this.write(')')
break
case SyntaxKind.GetRootCtxCall:
this.write('_.getRootCtx(')
this.writeExpressionList(node.args)
this.write(')')
break
case SyntaxKind.HelperCall:
this.write(`_.${node.name}(`)
this.writeExpressionList(node.args)
this.write(')')
break
case SyntaxKind.FunctionDefinition:
case SyntaxKind.SlotRendererDefinition:
return this.writeFunctionDefinition(node)
case SyntaxKind.FunctionCall:
this.writeSyntaxNode(node.fn)
Expand Down Expand Up @@ -115,6 +121,9 @@ export class JSEmitter extends Emitter {
this.writeSyntaxNode(node.value)
this.write(')')
break
case SyntaxKind.ComponentReferenceLiteral:
this.writeSyntaxNode(node.toMapLiteral())
break
case SyntaxKind.ReturnStatement:
this.nextLine('return ')
this.writeSyntaxNode(node.value)
Expand Down Expand Up @@ -189,7 +198,7 @@ export class JSEmitter extends Emitter {
this.writeBlockStatements(node.body)
}

public writeFunctionDefinition (node: FunctionDefinition) {
public writeFunctionDefinition (node: FunctionDefinition | SlotRendererDefinition) {
this.write(`function ${node.name} (`)
let first = true
for (const arg of node.args) {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/emitter.ts
Expand Up @@ -89,7 +89,7 @@ export class Emitter {
return this.code.length
}

private lastChar () {
protected lastChar () {
return this.code[this.size() - 1]
}
}
10 changes: 5 additions & 5 deletions test/unit/optimizers/merge-literal-add.spec.ts
@@ -1,22 +1,22 @@
import { RETURN, BINARY, STATMENT, L, I } from '../../../src/ast/renderer-ast-factory'
import { RETURN, BINARY, STATEMENT, L, I } from '../../../src/ast/renderer-ast-factory'
import { mergeLiteralAdd } from '../../../src/optimizers/merge-literal-add'
import { FunctionDefinition } from '../../../src/ast/renderer-ast-node'

describe('optimizers/merge-literal-add', () => {
it('should merge to successive html+=', () => {
const fn = new FunctionDefinition('', [], [
STATMENT(BINARY(I('html'), '+=', L('foo'))),
STATMENT(BINARY(I('html'), '+=', L('bar')))
STATEMENT(BINARY(I('html'), '+=', L('foo'))),
STATEMENT(BINARY(I('html'), '+=', L('bar')))
])
mergeLiteralAdd(fn)
expect(fn.body).toHaveLength(1)
expect(fn.body[0]).toHaveProperty('value.rhs.value', 'foobar')
})
it('should not merge if not successive', () => {
const fn = new FunctionDefinition('', [], [
STATMENT(BINARY(I('html'), '+=', L('foo'))),
STATEMENT(BINARY(I('html'), '+=', L('foo'))),
RETURN(I('html')),
STATMENT(BINARY(I('html'), '+=', L('bar')))
STATEMENT(BINARY(I('html'), '+=', L('bar')))
])
mergeLiteralAdd(fn)
expect(fn.body).toHaveLength(3)
Expand Down

0 comments on commit f8e8b92

Please sign in to comment.