ember-material-icons
Version:
Google Material icons for your ember-cli app
290 lines (222 loc) • 9.58 kB
text/typescript
import { CompiledProgram, CompiledBlock } from './compiled/blocks';
import { builder } from './compiler';
import OpcodeBuilder from './compiled/opcodes/builder';
import Environment from './environment';
import { Option } from '@glimmer/util';
import { SerializedTemplateBlock, TemplateMeta, SerializedBlock, Statement as SerializedStatement } from '@glimmer/wire-format';
import * as WireFormat from '@glimmer/wire-format';
import { entryPoint as entryPointTable, layout as layoutTable, block as blockTable } from './symbol-table';
import { Opaque, SymbolTable, ProgramSymbolTable } from '@glimmer/interfaces';
import {
STATEMENTS
} from './syntax/functions';
import {
SPECIALIZE
} from './syntax/specialize';
export type DeserializedStatement = WireFormat.Statement | WireFormat.Statements.Attribute | WireFormat.Statements.Argument;
export function compileStatement(statement: BaselineSyntax.AnyStatement, builder: OpcodeBuilder) {
let refined = SPECIALIZE.specialize(statement, builder.symbolTable);
STATEMENTS.compile(refined, builder);
}
export class Template {
constructor(public statements: BaselineSyntax.AnyStatement[], public symbolTable: SymbolTable) {}
}
export class Layout extends Template {
public symbolTable: ProgramSymbolTable;
}
export class EntryPoint extends Template {
private compiled: Option<CompiledProgram> = null;
public symbolTable: ProgramSymbolTable;
compile(env: Environment): CompiledProgram {
let compiled = this.compiled;
if (!compiled) {
let table = this.symbolTable;
let b = builder(env, table);
for (let i = 0; i < this.statements.length; i++) {
let statement = this.statements[i];
let refined = SPECIALIZE.specialize(statement, table);
STATEMENTS.compile(refined, b);
}
compiled = this.compiled = new CompiledProgram(b.start, b.end, this.symbolTable.size);
}
return compiled;
}
}
export class InlineBlock extends Template {
private compiled: Option<CompiledBlock> = null;
splat(builder: OpcodeBuilder) {
let table = builder.symbolTable;
let locals = table.getSymbols().locals;
if (locals) {
builder.pushChildScope();
builder.bindPositionalArgsForLocals(locals);
}
for (let i = 0; i < this.statements.length; i++) {
let statement = this.statements[i];
let refined = SPECIALIZE.specialize(statement, table);
STATEMENTS.compile(refined, builder);
}
if (locals) {
builder.popScope();
}
}
compile(env: Environment): CompiledBlock {
let compiled = this.compiled;
if (!compiled) {
let table = this.symbolTable;
let b = builder(env, table);
this.splat(b);
compiled = this.compiled = new CompiledBlock(b.start, b.end);
}
return compiled;
}
}
export class PartialBlock extends Template {
private compiled: Option<CompiledProgram> = null;
public symbolTable: ProgramSymbolTable;
compile(env: Environment): CompiledProgram {
let compiled = this.compiled;
if (!compiled) {
let table = this.symbolTable;
let b = builder(env, table);
for (let i = 0; i < this.statements.length; i++) {
let statement = this.statements[i];
let refined = SPECIALIZE.specialize(statement, table);
STATEMENTS.compile(refined, b);
}
compiled = this.compiled = new CompiledProgram(b.start, b.end, table.size);
}
return compiled;
}
}
export default class Scanner {
constructor(private block: SerializedTemplateBlock, private meta: TemplateMeta, private env: Environment) {
}
scanEntryPoint(): EntryPoint {
let { block, meta } = this;
let symbolTable = entryPointTable(meta);
let child = scanBlock(block, symbolTable, this.env);
return new EntryPoint(child.statements, symbolTable);
}
scanLayout(): Layout {
let { block, meta } = this;
let { named, yields, hasPartials } = block;
let symbolTable = layoutTable(meta, named, yields, hasPartials);
let child = scanBlock(block, symbolTable, this.env);
return new Layout(child.statements, symbolTable);
}
scanPartial(symbolTable: SymbolTable): PartialBlock {
let { block } = this;
let child = scanBlock(block, symbolTable, this.env);
return new PartialBlock(child.statements, symbolTable);
}
}
export function scanBlock({ statements }: SerializedBlock, symbolTable: SymbolTable, env: Environment): InlineBlock {
return new RawInlineBlock(env, symbolTable, statements).scan();
}
import { PublicVM } from './vm';
import { PathReference } from '@glimmer/reference';
export namespace BaselineSyntax {
import Core = WireFormat.Core;
const { Ops } = WireFormat;
// TODO: use symbols for sexp[0]?
export type ScannedComponent = [number, string, RawInlineBlock, WireFormat.Core.Hash, Option<RawInlineBlock>];
export const isScannedComponent = WireFormat.is<ScannedComponent>(Ops.ScannedComponent);
import Params = WireFormat.Core.Params;
import Hash = WireFormat.Core.Hash;
export type Block = InlineBlock;
export type OpenPrimitiveElement = [number, string, string[]];
export const isPrimitiveElement = WireFormat.is<OpenPrimitiveElement>(Ops.OpenPrimitiveElement);
export type OptimizedAppend = [number, WireFormat.Expression, boolean];
export const isOptimizedAppend = WireFormat.is<OptimizedAppend>(Ops.OptimizedAppend);
export type UnoptimizedAppend = [number, WireFormat.Expression, boolean];
export const isUnoptimizedAppend = WireFormat.is<UnoptimizedAppend>(Ops.UnoptimizedAppend);
export type AnyDynamicAttr = [number, string, WireFormat.Expression, Option<string>, boolean];
export const isAnyAttr = WireFormat.is<AnyDynamicAttr>(Ops.AnyDynamicAttr);
export type StaticPartial = [number, string];
export const isStaticPartial = WireFormat.is<StaticPartial>(Ops.StaticPartial);
export type DynamicPartial = [number, WireFormat.Expression];
export const isDynamicPartial = WireFormat.is<DynamicPartial>(Ops.DynamicPartial);
export type FunctionExpressionCallback<T> = (VM: PublicVM, symbolTable: SymbolTable) => PathReference<T>;
export type FunctionExpression = [number, FunctionExpressionCallback<Opaque>];
export const isFunctionExpression = WireFormat.is<FunctionExpression>(Ops.Function);
export type NestedBlock = [number, WireFormat.Core.Path, WireFormat.Core.Params, WireFormat.Core.Hash, Option<Block>, Option<Block>];
export const isNestedBlock = WireFormat.is<NestedBlock>(Ops.NestedBlock);
export type ScannedBlock = [number, Core.Path, Core.Params, Core.Hash, Option<RawInlineBlock>, Option<RawInlineBlock>];
export const isScannedBlock = WireFormat.is<ScannedBlock>(Ops.ScannedBlock);
export type Debugger = [number];
export const isDebugger = WireFormat.is<Debugger>(Ops.Debugger);
export type Args = [Params, Hash, Option<Block>, Option<Block>];
export namespace NestedBlock {
export function defaultBlock(sexp: NestedBlock): Option<InlineBlock> {
return sexp[4];
}
export function inverseBlock(sexp: NestedBlock): Option<InlineBlock> {
return sexp[5];
}
export function params(sexp: NestedBlock): WireFormat.Core.Params {
return sexp[2];
}
export function hash(sexp: NestedBlock): WireFormat.Core.Hash {
return sexp[3];
}
}
export type Statement =
ScannedComponent
| OpenPrimitiveElement
| OptimizedAppend
| UnoptimizedAppend
| StaticPartial
| DynamicPartial
| AnyDynamicAttr
| NestedBlock
| ScannedBlock
| Debugger
;
export type AnyStatement = Statement | WireFormat.Statement;
export type AnyExpression = FunctionExpression | WireFormat.Expression;
export type Program = AnyStatement[];
}
const { Ops } = WireFormat;
export class RawInlineBlock {
constructor(private env: Environment, private table: SymbolTable, private statements: SerializedStatement[]) {}
scan(): InlineBlock {
let buffer: BaselineSyntax.AnyStatement[] = [];
for(let i = 0; i < this.statements.length; i++) {
let statement = this.statements[i];
if (WireFormat.Statements.isBlock(statement)) {
buffer.push(this.specializeBlock(statement));
} else if (WireFormat.Statements.isComponent(statement)) {
buffer.push(...this.specializeComponent(statement));
} else {
buffer.push(statement);
}
}
return new InlineBlock(buffer, this.table);
}
private specializeBlock(block: WireFormat.Statements.Block): BaselineSyntax.ScannedBlock {
let [, path, params, hash, template, inverse] = block;
return [Ops.ScannedBlock, path, params, hash, this.child(template), this.child(inverse)];
}
private specializeComponent(sexp: WireFormat.Statements.Component): BaselineSyntax.AnyStatement[] {
let [, tag, component] = sexp;
if (this.env.hasComponentDefinition(tag, this.table)) {
let child = this.child(component);
let attrs = new RawInlineBlock(this.env, this.table, component.attrs);
return [[Ops.ScannedComponent, tag, attrs, component.args, child]];
} else {
let buf: BaselineSyntax.AnyStatement[] = [];
buf.push([Ops.OpenElement, tag, []]);
buf.push(...component.attrs);
buf.push([Ops.FlushElement]);
buf.push(...component.statements);
buf.push([Ops.CloseElement]);
return buf;
}
}
child(block: Option<SerializedBlock>): Option<RawInlineBlock> {
if (!block) return null;
let table = blockTable(this.table, block.locals);
return new RawInlineBlock(this.env, table, block.statements);
}
}