Skip to content

Instantly share code, notes, and snippets.

@nebrelbug

nebrelbug/Err.js Secret

Last active December 13, 2019 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nebrelbug/34c3bba19b54c4ba7973b1337a884449 to your computer and use it in GitHub Desktop.
Save nebrelbug/34c3bba19b54c4ba7973b1337a884449 to your computer and use it in GitHub Desktop.
Parser v32: Newbie
// 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
// 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