UNPKG

ember-material-icons

Version:

Google Material icons for your ember-cli app

290 lines (222 loc) 9.58 kB
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); } }