firescript
Version:
Firescript transpiler
200 lines (165 loc) • 5.09 kB
JavaScript
const superconf = require('superconf')
class NodeMapping {
constructor (opts) {
opts = opts || {}
this.confDir = opts.confDir
if (!this.confDir) {
throw new Error('The Parser.confDir parameter must be set!')
}
const nodeMapping = superconf('nodeMapping', {
cwd: this.confDir
})
this.nodeMapping = this.parseMapping(nodeMapping.mapping)
}
parse (mappingPattern) {
// const patterns = mappingPattern.split(/(?<!(".+"))>/g)
let startIndex = 0
// const node = mappingPattern.slice(0, startIndex)
const len = mappingPattern.length
const patterns = []
let goTo = null
for (let i = 0; i < len; i++) {
if (goTo) {
if (mappingPattern.charAt(i) === goTo) {
goTo = null
}
continue
}
if (mappingPattern.charAt(i) === '>') {
patterns.push(mappingPattern.slice(startIndex, i - 1).trim())
startIndex = i + 1
}
if (mappingPattern.charAt(i) === '\\') {
continue
}
if (mappingPattern.charAt(i) === '"') {
goTo = '"'
continue
}
if (mappingPattern.charAt(i) === '/') {
goTo = '/'
continue
}
if (mappingPattern.charAt(i) === '[') {
goTo = ']'
continue
}
}
if (startIndex < len) {
patterns.push(mappingPattern.slice(startIndex))
}
const mapping = patterns.map((pat) => {
const nodeMapping = pat.trim().match(/([a-zA-Z-]+)(?:\s+(?:"(.+?)"|\[(.+?)\]|\/(.+)\/))?/)
// console.log('NDD', nodeMapping)
const value = nodeMapping[2]
? nodeMapping[2] : nodeMapping[3]
? nodeMapping[3].split(/,/g) : nodeMapping[4]
? new RegExp(nodeMapping[4]) : null
if (/^[A-Z]/.test(nodeMapping[1])) {
return {
node: nodeMapping[1]
}
}
return {
type: nodeMapping[1],
value: value
}
})
// this.mapping = mapping
return {
mapping: mapping,
// test: (token) => mapping.every((definition, offset) => {
// if (!token) {
// return false
// }
//
// if (definition.value && Array.isArray(definition.value)) {
// return definition.value.indexOf(token.value) >= 0
// } else if (definition.value && definition.value instanceof RegExp) {
// return definition.value.test(token.value)
// } else if (definition.value && token.value !== definition.value) {
// return false
// }
//
// return Array.isArray(definition.type)
// ? definition.type.some((t) => t === token.type)
// : token.type === definition.type
// })
test: (node, tokenBuffer) => {
let bufferOffset = -1
return mapping.every((definition) => {
if (definition.node) {
return node.type === definition.node
} else {
bufferOffset += 1
}
return tokenBuffer.match(definition.type, definition.value || definition.valueReg, bufferOffset)
})
}
}
}
/**
* Sort definitions
*
* higher count of ">"
* has key + value
*/
parseMapping (nodeMapping) {
return Object.entries(nodeMapping).map(([ mapping, definition ]) => {
return Object.assign(this.parse(mapping), definition)
}).sort((a, b) => {
const aWeight = a.weight || 0
const bWeight = b.weight || 0
if (aWeight > bWeight) {
return -1
}
if (aWeight < bWeight) {
return 1
}
if (a.mapping.length > b.mapping.length) {
return -1
}
if (a.mapping.length === b.mapping.length) {
for (let i = 0; i < a.mapping.length; i++) {
if (a.mapping[i].value && !b.mapping[i].value) {
return -1
}
if (!a.mapping[i].value && b.mapping[i].value) {
return 1
}
// sort longer value up
if (a.mapping[i].value && b.mapping[i].value) {
if (a.mapping[i].value.length > b.mapping[i].value.length) {
return -1
}
if (a.mapping[i].value.length < b.mapping[i].value.length) {
return 1
}
}
}
return 0
}
return 1
})
}
resolve (node, tokenBuffer, scope) {
const definition = this.nodeMapping.find((mapping, index) => {
// console.log('FIND', scope.type, mapping.name, node.type)
if (!mapping.allowNested && (mapping.name === node.type || (scope && mapping.name === scope.type))) {
return false
}
if (!mapping.test(node, tokenBuffer)) {
return false
}
// console.log('MAPPINGTYPE', scope)
return (!mapping.scopes && mapping.name) || (scope && mapping.scopes[scope.type]) || mapping.name
})
if (definition) {
if (definition.scopes && scope && definition.scopes[scope.type]) {
return definition.scopes[scope.type]
}
return definition.name
}
}
}
module.exports = NodeMapping