~kylep/pipes

a9bdfa8a0117a708df0ba41e4560e86c103d9d4d — Kyle Perik a month ago 4de95e6
Add runtime state
3 files changed, 88 insertions(+), 9 deletions(-)

M src/device.js
M src/parser.js
M src/runtime.js
M src/device.js => src/device.js +8 -2
@@ 36,13 36,13 @@ function initDevices () {
  canvas.addEventListener('mousemove', e => {
    processEvent(['mousemove', { x: e.offsetX, y: e.offsetY }]);
  })
  window.addEventListener('mousedown', e => {
  canvas.addEventListener('mousedown', e => {
    processEvent([
      'mousedown',
      { x: e.offsetX, y: e.offsetY }
    ]);
  })
  window.addEventListener('mouseup', e => {
  canvas.addEventListener('mouseup', e => {
    processEvent([
      'mouseup',
      { x: e.offsetX, y: e.offsetY }


@@ 176,4 176,10 @@ function handle (event) {

function register (program) {
  runningProgram = program
  runtimeRefs = Object.keys(program.refs).map(ref => (
    {
      name: ref,
      value: buildResult(program.refs[ref], {}, {})
    }
  ))
}

M src/parser.js => src/parser.js +68 -6
@@ 258,11 258,23 @@ function parseGroups (tokenGroups) {
          ...r,
          mode: 'define'
        }
      } else if (token === 'ref') {
        return {
          ...r,
          mode: 'ref'
        }
      } else if (token === '|') {
        return {
          ...r,
          mode: 'pending'
        }
      } else if (token === '->') {
        return {
          ...r,
          mode: 'assign'
        }
      } else if (token === ';') {
        return r
      } else {
        return {
          ...r,


@@ 271,7 283,7 @@ function parseGroups (tokenGroups) {
        }
      }
    } else if (r.mode === 'pending') {
      if (token === '|') {
      if (['|', '->'].includes(token)) {
        let result;
        if (r.match) {
          result = processPatternMatch(r, r.pendingTokens)


@@ 279,6 291,12 @@ function parseGroups (tokenGroups) {
          result = processPipeToken(r, r.pendingTokens)
        }
        if (result) {
          if (token === '->') {
            return {
              ...result, isCondition: undefined, pendingTokens: [],
              mode: 'assign'
            }
          }
          return { ...result, isCondition: undefined, pendingTokens: [] }
        }
      } else if (token === ':') {


@@ 313,6 331,42 @@ function parseGroups (tokenGroups) {
          pendingTokens: r.pendingTokens.concat([token]),
        }
      }
    } else if (r.mode === 'assign') {
      return {
        ...r,
        mode: null,
        pendingTokens: [],
        pendingPatterns: [],
        patterns: r.patterns.concat([r.pendingPatterns.concat([{
          type: ASSIGN,
          value: token
        }])])
      }
    } else if (r.mode === 'ref') {
      if (!r.key) {
        return {
          ...r,
          key: token
        }
      }
      if (token === ';') {
        const newRefs = {
          ...r.refs,
          [r.key]: parsePatternFragment(r.pendingTokens)
        }
        return {
          ...r,
          key: null,
          pendingTokens: [],
          refs: newRefs,
          mode: null
        }
      } else {
        return {
          ...r,
          pendingTokens: r.pendingTokens.concat([token])
        }
      }
    } else if (r.mode === 'define') {
      if (!r.key) {
        return {


@@ 321,8 375,10 @@ function parseGroups (tokenGroups) {
        }
      }
      if (token === ';') {
        const newDefinitions = {...r.definitions}
        newDefinitions[r.key] = parseGroups(r.pendingTokens).patterns
        const newDefinitions = {
          ...r.definitions,
          [r.key]: parseGroups(r.pendingTokens).patterns
        }
        return {
          ...r,
          key: null,


@@ 341,6 397,7 @@ function parseGroups (tokenGroups) {
  }, {
    patterns: [],
    definitions: {},
    refs: {},
    pendingPatterns: [],
    pendingTokens: [],
    mode: null


@@ 353,7 410,8 @@ function parseGroups (tokenGroups) {
    patterns = patterns.concat([result.pendingPatterns])
  }
  const definitions = result.definitions
  return { patterns, definitions }
  const refs = result.refs
  return { patterns, definitions, refs }
}

function tokenRepr (tokens) {


@@ 374,9 432,13 @@ function tokenRepr (tokens) {
  }).join('')
}

function getTokens(body) {
  const tokenRegex = /(->|{|}|\[|\]|\n|'|,|:|;|\?|@|\s+|[A-Za-z]+)/g;
  return body.split(tokenRegex).filter(token => token)
}

function parse (body) {
  const tokenRegex = /({|}|\[|\]|\n|'|,|:|;|\?|@|\s+|[A-Za-z]+)/g;
  const allTokens = body.split(tokenRegex).filter(token => token)
  const allTokens = getTokens(body)

  const tokenGroups = groupTokens(allTokens)
  const result = parseGroups(tokenGroups)

M src/runtime.js => src/runtime.js +12 -1
@@ 7,6 7,9 @@ const REST = 'rest'
const GROUP = 'group'
const PATTERN = 'pattern'
const BUNDLE = 'bundle'
const ASSIGN = 'assign'

let runtimeRefs = []

function checkMatch (data, match, refs=[]) {
  if (match.type === LIT) {


@@ 159,7 162,7 @@ function buildResult (result, refs, defs) {
    }, [[]])
    return listResult
  } else if (result.type === REF) {
    const reference = refs.find(ref => ref.name === result.value)
    const reference = refs.concat(runtimeRefs).find(ref => ref.name === result.value)
    if (!reference) {
      throw new Error(`Reference not found: ${result.value}`)
    }


@@ 188,6 191,14 @@ function handlePipe (data, pipe, definitions) {
  } else if (pipe.type === BUNDLE) {
    const result = handlePipe(data, pipe.value, definitions)
    return [result]
  } else if (pipe.type === ASSIGN) {
    runtimeRefs = runtimeRefs.map(ref => {
      if (ref.name === pipe.value) {
        return { name: ref.name, value: data }
      }
      return ref
    });
    return [];
  } else if (pipe.type === PATTERN) {
    const match = checkMatch(data, pipe.match)
    if (!match.matched) {