-
-
Save nebrelbug/34c3bba19b54c4ba7973b1337a884449 to your computer and use it in GitHub Desktop.
Parser v32: Newbie
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// v 1.0.32 | |
function SqrlErr (message) { | |
var up = Error(message + '\n') // e.name is 'Error' | |
up.name = 'Squirrelly Error' | |
up.stack = '' | |
} | |
// See : | |
// function SqrlErr (message) { | |
// this.message = message + '\n' // e.name is 'Error' | |
// this.name = 'Squirrelly Error' | |
// } | |
// SqrlErr.prototype = new Error | |
function ParseErr (message, val, str, indx) { | |
var whitespace = str | |
.slice(0, indx) // +2 because of {{ | |
.split(/\n/) | |
// console.log('whitespace: \n' + JSON.stringify(whitespace)) | |
var lineNo = whitespace.length | |
var colNo = whitespace[lineNo - 1].length + 1 | |
message += | |
' at line ' + | |
lineNo + | |
' col ' + | |
colNo + | |
':\n\n' + | |
' ' + | |
str.split(/\n/)[lineNo - 1] + | |
'\n' + | |
' ' + | |
Array(colNo).join(' ') + | |
'^' | |
SqrlErr(message) | |
} | |
module.exports.ParseErr = ParseErr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Version 1.0.32 | |
var ParseErr = require('./Err').ParseErr | |
module.exports = function Parse (str, tagOpen, tagClose) { | |
var powerchars = new RegExp( | |
'(["\'`\\\\|()]|=>)|(\\/\\*[^]*?\\*\\/)|((\\/)?(-|_)?' + tagClose + ')', | |
'g' | |
) | |
var tagOpenLength = tagOpen.length | |
var tagOpenIndex = 0 | |
var startInd = 0 | |
function parseTag () { | |
// console.log(JSON.stringify(match)) | |
var currentObj = {} // start, end | |
if (str[startInd] === '-' || str[startInd] === '_') { | |
currentObj.wsLeft = str[startInd] | |
startInd += 1 | |
} | |
var numParens = 0 | |
var filterNumber = 0 | |
var firstChar = str[startInd] | |
var currentAttribute = 'c' // default - Valid values: 'c'=content, 'f'=filter, 'fp'=filter params, 'p'=param, 'n'=name | |
var currentType = firstChar // Default | |
startInd += 1 // assume we're gonna skip the first character | |
if (firstChar === '~' || firstChar === '#' || firstChar === '/') { | |
currentAttribute = 'n' | |
} else if (firstChar === '!' || firstChar === '?') { | |
// ? for custom | |
// Do nothing, we're keeping currentAttribute as 'c' | |
} else { | |
currentType = 'r' | |
startInd -= 1 | |
} | |
function isEscaped (ind) { | |
var esc = false | |
var i = 1 | |
while (str[ind - i] === '\\') { | |
esc = !esc | |
i++ | |
} | |
return esc | |
} | |
function addAttrValue (indx, strng) { | |
var valUnprocessed = str.slice(startInd, indx) + (strng || '') | |
// console.log(valUnprocessed) | |
var val = valUnprocessed.trim() | |
if (currentAttribute === 'f') { | |
currentObj.f[filterNumber - 1][0] += val // filterNumber - 1 because first filter: 0->1, but zero-indexed arrays | |
} else if (currentAttribute === 'fp') { | |
currentObj.f[filterNumber - 1][1] += val | |
} else if (currentAttribute === 'err') { | |
if (val) { | |
var found = valUnprocessed.search(/\S/) | |
ParseErr( | |
'invalid syntax', | |
val, | |
str, | |
startInd + found + tagOpenLength // TODO: CHANGE TO STARTTAG.LENGTH | |
) | |
} | |
} else if (currentAttribute !== '') { | |
if (currentObj[currentAttribute]) { | |
currentObj[currentAttribute] += val | |
} else { | |
currentObj[currentAttribute] = val | |
} | |
} | |
startInd = indx + 1 | |
} | |
var m | |
while ((m = powerchars.exec(str, startInd)) !== null) { | |
var char = m[1] | |
var comment = m[2] | |
var tagClose = m[3] | |
var slash = m[4] | |
var wsControl = m[5] | |
var i = m.index | |
if (char) { | |
// Power character | |
if ((char === '"') | (char === '`') | (char === "'")) { | |
// convert to regex test? | |
var newInd = str.indexOf(char, m.index) | |
while (isEscaped(newInd)) { | |
newInd = str.indexOf(char, m.index) | |
} | |
powerchars.lastIndex = newInd + 1 | |
} else if (char === '(') { | |
if (numParens === 0) { | |
if (currentAttribute === 'n') { | |
addAttrValue(i) | |
currentAttribute = 'p' | |
} else if (currentAttribute === 'f') { | |
addAttrValue(i) | |
currentAttribute = 'fp' | |
} | |
} | |
numParens++ | |
} else if (char === ')' /* && !escaped */) { | |
// A \( shouldn't occur in real JS | |
numParens-- | |
if (numParens === 0 && currentAttribute !== 'c') { | |
// Then it's closing a filter, block, or helper | |
addAttrValue(i) | |
currentAttribute = 'err' // Reset the current attribute | |
} | |
} else if (numParens === 0 && char === '|') { | |
if (currentAttribute !== 'err') { | |
addAttrValue(i) | |
} | |
currentAttribute = 'f' | |
if (filterNumber === 0) { | |
currentObj.f = [] // Initial assign | |
} | |
filterNumber++ | |
currentObj.f[filterNumber - 1] = ['', ''] | |
} else if (char === '=>') { | |
addAttrValue(i) | |
startInd += 1 // this is 2 chars | |
currentAttribute = 'res' | |
} | |
} else if (comment) { | |
// startInd += comment.length - 1 | |
} else if (tagClose) { | |
addAttrValue(i) | |
startInd += tagClose.length - 1 | |
currentObj.wsRight = wsControl | |
if (slash && currentType === '~') { | |
currentType = 's' | |
} // TODO throw err | |
currentObj.t = currentType | |
return currentObj | |
} | |
} | |
} | |
function parseContext (parentObj, firstParse) { | |
var lastBlock = false | |
var buffer = [] | |
function pushString (indx) { | |
if (startInd !== indx) { | |
buffer.push( | |
str | |
.slice(startInd, indx) | |
.replace(/\\/g, '\\\\') | |
.replace(/'/g, "\\'") | |
) | |
} | |
} | |
// Random TODO: parentObj.b doesn't need to have t: # | |
while ((tagOpenIndex = str.indexOf(tagOpen, startInd)) !== -1) { | |
// Loop through all of the tagOpen's | |
pushString(tagOpenIndex) | |
startInd = tagOpenIndex + tagOpenLength | |
var currentObj = parseTag() | |
// ===== NOW ADD THE OBJECT TO OUR BUFFER ===== | |
var currentType = currentObj.t | |
if (currentType === '~') { | |
currentObj = parseContext(currentObj) // No need to pass in false, undefined is falsy | |
buffer.push(currentObj) | |
} else if (currentType === '/') { | |
if (parentObj.n === currentObj.n) { | |
if (lastBlock) { | |
lastBlock.d = buffer | |
parentObj.b.push(lastBlock) | |
} else { | |
parentObj.d = buffer | |
} | |
// console.log('parentObj: ' + JSON.stringify(parentObj)) | |
return parentObj | |
} else { | |
throw Error("Helper start and end don't match") | |
} | |
} else if (currentType === '#') { | |
if (lastBlock) { | |
lastBlock.d = buffer | |
parentObj.b.push(lastBlock) | |
} else { | |
parentObj.d = buffer | |
parentObj.b = [] // Create a new array to store the parent's blocks | |
} | |
lastBlock = currentObj // Set the 'lastBlock' object to the value of the current block | |
buffer = [] | |
} else { | |
buffer.push(currentObj) | |
} | |
// ===== DONE ADDING OBJECT TO BUFFER ===== | |
} | |
if (firstParse) { | |
// TODO: more intuitive | |
pushString(str.length) | |
parentObj.d = buffer | |
return parentObj | |
} | |
return parentObj | |
} | |
var parseResult = parseContext({}, true) | |
// console.log(JSON.stringify(parseResult)) | |
return parseResult.d // Parse the very outside context | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment