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) {