This repository has been archived on 2023-08-29. You can view files and clone it, but cannot push or open issues/pull-requests.
yutent
/
anot.js
Archived
1
0
Fork 0
anot.js/src/12-parser.js

327 lines
9.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

var keyMap = {}
var keys = [
'break,case,catch,continue,debugger,default,delete,do,else,false',
'finally,for,function,if,in,instanceof,new,null,return,switch,this',
'throw,true,try,typeof,var,void,while,with' /* 关键字*/,
'abstract,boolean,byte,char,class,const,double,enum,export,extends',
'final,float,goto,implements,import,int,interface,long,native',
'package,private,protected,public,short,static,super,synchronized',
'throws,transient,volatile' /*保留字*/,
'arguments,let,yield,async,await,undefined'
].join(',')
keys.replace(/\w+/g, function(a) {
keyMap[a] = true
})
var ridentStart = /[a-z_$]/i
var rwhiteSpace = /[\s\uFEFF\xA0]/
function getIdent(input, lastIndex) {
var result = []
var subroutine = !!lastIndex
lastIndex = lastIndex || 0
//将表达式中的标识符抽取出来
var state = 'unknown'
var variable = ''
for (var i = 0; i < input.length; i++) {
var c = input.charAt(i)
if (c === "'" || c === '"') {
//字符串开始
if (state === 'unknown') {
state = c
} else if (state === c) {
//字符串结束
state = 'unknown'
}
} else if (c === '\\') {
if (state === "'" || state === '"') {
i++
}
} else if (ridentStart.test(c)) {
//碰到标识符
if (state === 'unknown') {
state = 'variable'
variable = c
} else if (state === 'maybePath') {
variable = result.pop()
variable += '.' + c
state = 'variable'
} else if (state === 'variable') {
variable += c
}
} else if (/\w/.test(c)) {
if (state === 'variable') {
variable += c
}
} else if (c === '.') {
if (state === 'variable') {
if (variable) {
result.push(variable)
variable = ''
state = 'maybePath'
}
}
} else if (c === '[') {
if (state === 'variable' || state === 'maybePath') {
if (variable) {
//如果前面存在变量,收集它
result.push(variable)
variable = ''
}
var lastLength = result.length
var last = result[lastLength - 1]
var innerResult = getIdent(input.slice(i), i)
if (innerResult.length) {
//如果括号中存在变量,那么这里添加通配符
result[lastLength - 1] = last + '.*'
result = innerResult.concat(result)
} else {
//如果括号中的东西是确定的,直接转换为其子属性
var content = input.slice(i + 1, innerResult.i)
try {
var text = scpCompile(['return ' + content])()
result[lastLength - 1] = last + '.' + text
} catch (e) {}
}
state = 'maybePath' //]后面可能还接东西
i = innerResult.i
}
} else if (c === ']') {
if (subroutine) {
result.i = i + lastIndex
addVar(result, variable)
return result
}
} else if (rwhiteSpace.test(c) && c !== '\r' && c !== '\n') {
if (state === 'variable') {
if (addVar(result, variable)) {
state = 'maybePath' // aaa . bbb 这样的情况
}
variable = ''
}
} else {
addVar(result, variable)
state = 'unknown'
variable = ''
}
}
addVar(result, variable)
return result
}
function addVar(array, element) {
if (element && !keyMap[element]) {
array.push(element)
return true
}
}
function addAssign(vars, vmodel, name, binding) {
var ret = []
var prefix = ' = ' + name + '.'
for (var i = vars.length, prop; (prop = vars[--i]); ) {
var arr = prop.split('.')
var first = arr[0]
if (vmodel.hasOwnProperty(first)) {
// log(first, prop, prefix, vmodel)
ret.push(first + prefix + first)
binding.observers.push({
v: vmodel,
p: prop,
type: Anot.type(vmodel[first])
})
vars.splice(i, 1)
}
}
return ret
}
var rproxy = /(proxy\-[a-z]+)\-[\-0-9a-f]+$/
var variablePool = new Cache(218)
//缓存求值函数,以便多次利用
var evaluatorPool = new Cache(128)
function getVars(expr) {
expr = expr.trim()
var ret = variablePool.get(expr)
if (ret) {
return ret.concat()
}
var array = getIdent(expr)
var uniq = {}
var result = []
for (var i = 0, el; (el = array[i++]); ) {
if (!uniq[el]) {
uniq[el] = 1
result.push(el)
}
}
return variablePool.put(expr, result).concat()
}
function parseExpr(expr, vmodels, binding) {
var filters = binding.filters
if (typeof filters === 'string' && filters.trim() && !binding._filters) {
binding._filters = parseFilter(filters.trim())
}
var vars = getVars(expr)
var expose = new Date() - 0
var assigns = []
var names = []
var args = []
binding.observers = []
for (var i = 0, sn = vmodels.length; i < sn; i++) {
if (vars.length) {
var name = 'vm' + expose + '_' + i
names.push(name)
args.push(vmodels[i])
assigns.push.apply(assigns, addAssign(vars, vmodels[i], name, binding))
}
}
binding.args = args
var dataType = binding.type
var exprId =
vmodels.map(function(el) {
return String(el.$id).replace(rproxy, '$1')
}) +
expr +
dataType
// log(expr, '---------------', assigns)
var getter = evaluatorPool.get(exprId) //直接从缓存,免得重复生成
if (getter) {
if (dataType === 'duplex') {
var setter = evaluatorPool.get(exprId + 'setter')
binding.setter = setter.apply(setter, binding.args)
}
return (binding.getter = getter)
}
// expr的字段不可枚举时,补上一个随机变量, 避免抛出异常
if (!assigns.length) {
assigns.push('fix' + expose)
}
if (dataType === 'duplex') {
var nameOne = {}
assigns.forEach(function(a) {
var arr = a.split('=')
nameOne[arr[0].trim()] = arr[1].trim()
})
expr = expr.replace(/[\$\w]+/, function(a) {
return nameOne[a] ? nameOne[a] : a
})
/* jshint ignore:start */
var fn2 = scpCompile(
names.concat(
'"use strict";\n return function(vvv){' + expr + ' = vvv\n}\n'
)
)
/* jshint ignore:end */
evaluatorPool.put(exprId + 'setter', fn2)
binding.setter = fn2.apply(fn2, binding.args)
}
if (dataType === 'on') {
//事件绑定
if (expr.indexOf('(') === -1) {
expr += '.call(' + names[names.length - 1] + ', $event)'
} else {
expr = expr.replace('(', '.call(' + names[names.length - 1] + ', ')
}
names.push('$event')
expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错需要Function("return ;")
var lastIndex = expr.lastIndexOf('\nreturn')
var header = expr.slice(0, lastIndex)
var footer = expr.slice(lastIndex)
expr = header + '\n' + footer
} else {
// 对于非事件绑定的方法, 同样绑定到vm上
binding.observers.forEach(function(it) {
if (it.type === 'function') {
// log(it, expr)
var reg = new RegExp(it.p + '\\(([^)]*)\\)', 'g')
expr = expr.replace(reg, function(s, m) {
m = m.trim()
return (
it.p +
'.call(' +
names[names.length - 1] +
(m ? ', ' + m : '') +
')'
)
})
}
})
expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错需要Function("return ;")
}
/* jshint ignore:start */
getter = scpCompile(
names.concat(
"'use strict';\ntry{\n var " +
assigns.join(',\n ') +
expr +
'\n}catch(e){console.log(e)}'
)
)
/* jshint ignore:end */
return evaluatorPool.put(exprId, getter)
}
function normalizeExpr(code) {
var hasExpr = rexpr.test(code) //比如:class="width{{w}}"的情况
if (hasExpr) {
var array = scanExpr(code)
if (array.length === 1) {
return array[0].expr
}
return array
.map(function(el) {
return el.type ? '(' + el.expr + ')' : quote(el.expr)
})
.join(' + ')
} else {
return code
}
}
Anot.normalizeExpr = normalizeExpr
Anot.parseExprProxy = parseExpr
var rthimRightParentheses = /\)\s*$/
var rthimOtherParentheses = /\)\s*\|/g
var rquoteFilterName = /\|\s*([$\w]+)/g
var rpatchBracket = /"\s*\["/g
var rthimLeftParentheses = /"\s*\(/g
function parseFilter(filters) {
filters =
filters
.replace(rthimRightParentheses, '') //处理最后的小括号
.replace(rthimOtherParentheses, function() {
//处理其他小括号
return '],|'
})
.replace(rquoteFilterName, function(a, b) {
//处理|及它后面的过滤器的名字
return '[' + quote(b)
})
.replace(rpatchBracket, function() {
return '"],["'
})
.replace(rthimLeftParentheses, function() {
return '",'
}) + ']'
/* jshint ignore:start */
return scpCompile(['return [' + filters + ']'])()
/* jshint ignore:end */
}
/*********************************************************************
* 编译系统 *
**********************************************************************/
var quote = JSON.stringify
Anot 是Anot not only templateEngine的缩写。 它是一款迷你,易用、高性能的前端MVVM框架, fork于avalon。进行了大量的重构,精简部分冗余的API, 同时针对组件拓展进行了优化。
JavaScript 100%