- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
开发人员创建了一个非常简单的程序:
var a = 6;
var b = 7
console.log(a * b);
我想确保开发人员使用分号,因为我不相信所有开发人员都知道所有 ASI规则。由于我将添加其他代码质量检查,因此我想使用 Esprima生成 AST要检查的代码。当使用 Esprima online parser 解析上面的简单程序时(选中“基于行和列”选项),the following structure is created :
{
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 19
}
},
"type": "Program",
"body": [
{
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 10
}
},
"type": "VariableDeclaration",
"declarations": [
{
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 9
}
},
"type": "VariableDeclarator",
"id": {
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 5
}
},
"type": "Identifier",
"name": "a"
},
"init": {
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 1,
"column": 9
}
},
"type": "Literal",
"value": 6,
"raw": "6"
}
}
],
"kind": "var"
},
{
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 3,
"column": 0
}
},
"type": "VariableDeclaration",
"declarations": [
{
"loc": {
"start": {
"line": 2,
"column": 4
},
"end": {
"line": 2,
"column": 9
}
},
"type": "VariableDeclarator",
"id": {
"loc": {
"start": {
"line": 2,
"column": 4
},
"end": {
"line": 2,
"column": 5
}
},
"type": "Identifier",
"name": "b"
},
"init": {
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 9
}
},
"type": "Literal",
"value": 7,
"raw": "7"
}
}
],
"kind": "var"
},
{
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 19
}
},
"type": "ExpressionStatement",
"expression": {
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 18
}
},
"type": "CallExpression",
"callee": {
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 11
}
},
"type": "MemberExpression",
"computed": false,
"object": {
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 7
}
},
"type": "Identifier",
"name": "console"
},
"property": {
"loc": {
"start": {
"line": 3,
"column": 8
},
"end": {
"line": 3,
"column": 11
}
},
"type": "Identifier",
"name": "log"
}
},
"arguments": [
{
"loc": {
"start": {
"line": 3,
"column": 12
},
"end": {
"line": 3,
"column": 17
}
},
"type": "BinaryExpression",
"operator": "*",
"left": {
"loc": {
"start": {
"line": 3,
"column": 12
},
"end": {
"line": 3,
"column": 13
}
},
"type": "Identifier",
"name": "a"
},
"right": {
"loc": {
"start": {
"line": 3,
"column": 16
},
"end": {
"line": 3,
"column": 17
}
},
"type": "Identifier",
"name": "b"
}
}
]
}
}
]
}
我该如何检查是否使用了分号?我可以推断第二行可能没有使用其中一个,因为 AST 中的第二个 VariableDeclaration
显示它以 {line: 3, column: 0}
结束,如下所示.
其他使用 Esprima 的工具也是这样做的吗?检查 \r\n
与 \n
行结尾怎么样? Esprima 不是执行此任务的正确工具吗?
与我分享这个问题的一位同事告诉我,我“可能需要解析树”,这样我就可以获得 token 列表。这样就解决了我的部分问题。以下是 Esprima 提供的代币:
[
{
"type": "Keyword",
"value": "var"
},
{
"type": "Identifier",
"value": "a"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "Numeric",
"value": "6"
},
{
"type": "Punctuator",
"value": ";"
},
{
"type": "Keyword",
"value": "var"
},
{
"type": "Identifier",
"value": "b"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "Numeric",
"value": "7"
},
{
"type": "Identifier",
"value": "console"
},
{
"type": "Punctuator",
"value": "."
},
{
"type": "Identifier",
"value": "log"
},
{
"type": "Punctuator",
"value": "("
},
{
"type": "Identifier",
"value": "a"
},
{
"type": "Punctuator",
"value": "*"
},
{
"type": "Identifier",
"value": "b"
},
{
"type": "Punctuator",
"value": ")"
},
{
"type": "Punctuator",
"value": ";"
}
]
现在我需要弄清楚如何将此标记列表与 AST 结合使用,以告诉我应该在第 2 行有一个分号。
最佳答案
要捕获 JavaScript 解释器无法捕获的逻辑或协议(protocol)错误(例如,始终以分号终止语句),您应该编写自己的状态机来对语法进行建模。对于您给出的示例,这是 CoffeeScript + Node.js 中的一种方法:
esprima = require 'esprima'
p_type = (is_valid) -> (token) -> is_valid(token.type)
p_value = (is_valid) -> (token) -> is_valid(token.value)
p_is = (target) -> (value) -> value is target
p_in = (targets...) -> (value) -> targets.indexOf(value) >= 0
p_tautology = () -> true
p_disjoin = (fs...) ->
switch fs.length
when 0
p_tautology
when 1
[f] = fs
(value) -> f(value)
when 2
[f, g] = fs
(value) -> f(value) || g(value)
else
[f, gs...] = fs
g = p_disjoin.apply(null, gs)
(value) -> f(value) || g(value)
p_conjoin = (fs...) ->
switch fs.length
when 0
p_tautology
when 1
[f] = fs
(value) -> f(value)
when 2
[f, g] = fs
(value) -> f(value) && g(value)
else
[f, gs...] = fs
g = p_conjoin.apply(null, gs)
(value) -> f(value) && g(value)
f_type = (token) -> token.type
f_value = (token) -> token.value
f_constant = (value) -> () -> value
f_identity = (x) -> x
f_token = (fn) -> (token) -> fn(token)
f_transition = (dispatch, transition) -> (token) -> transition[dispatch token]
f_default = (default_value, transition_fn) -> (token) -> transition_fn(token) || default_value
to_string = (value) ->
if value is null
'null'
else if value is `undefined`
'undefined'
else if typeof value is 'string'
'"' + value + '"'
else if typeof value.length is 'number' and value.length >= 0
elems = []
for e in value
elems.push to_string(e)
'[' + elems.join(', ') + ']'
else if typeof value is 'object'
if value.toString is Object::toString
attrs = []
for own k,v of value
attrs.push k + ': ' + to_string(v)
'{' + attrs.join(', ') + '}'
else
value.toString()
else
value.toString()
root =
is_valid: p_disjoin(
p_conjoin(p_type(p_is 'Keyword'), p_value(p_is 'var')),
p_type(p_is 'Identifier')
)
next_label: f_transition f_type, 'Keyword': 'variable_declaration', 'Identifier': 'identifier'
handle_error: (tokens, index) ->
if index > 0
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected variable "+
"declaration after #{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
else
curr_token = tokens[index]
{line, column} = curr_token.loc.start
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected variable "+
"declaration but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
identifier: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_in '.')
next_label: f_transition f_value, '.': 'membership'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected '.' after "+
"#{to_string prev_token.value}, but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
membership: () ->
is_valid: p_type(p_is 'Identifier')
next_label: f_constant 'invocation'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected an identifier "+
"after #{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
transition:
invocation: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_is '(')
next_label: f_constant 'identifier'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected '(' after "+
"#{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
transition:
identifier: () ->
is_valid: p_type(p_in 'Identifier')
next_label: f_constant 'punctuator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected "+
"an identifier after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
punctuator: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_in '*')
next_label: f_transition f_value, '*': 'identifier'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: "+
"Expected a binary operator after "+
"#{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
transition:
identifier: () ->
is_valid: p_conjoin p_type(p_is 'Identifier')
next_label: f_constant 'punctuator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected "+
"an identifier after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
punctuator: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_is ')')
next_label: f_constant 'punctuator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: "+
"Expected ')' after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
punctuator: () ->
is_valid: f_constant p_type(p_is 'Punctuator'), p_value(p_is ';')
next_label: f_transition f_value, ';': 'terminator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: "+
"Expected ';' after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
terminator: () -> root
variable_declaration: () ->
is_valid: p_type(p_is 'Identifier')
next_label: f_constant 'punctuator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected an identifier "+
"after #{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
transition:
punctuator: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_in '=', ',', ';')
next_label: f_token f_transition f_value, '=': 'assignment', ',': 'separator', ';': 'terminator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected '=', ',', "+
"or ';' after #{to_string prev_token.value}, but received "+
"#{to_string curr_token.value}\n")
process.exit(1)
transition:
assignment: () ->
is_valid: p_type(p_in 'Boolean', 'Identifier', 'Null', 'Numeric', 'String', 'RegularExpression')
next_label: f_constant 'punctuator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column #{1 + column}: Expected a "+
"literal or an identifier after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
punctuator: () ->
is_valid: p_conjoin p_type(p_is 'Punctuator'), p_value(p_in ',', ';', '.', '(', '{')
next_label: f_transition f_value, ',': 'identifier', ';': 'terminator'
handle_error: (tokens, index) ->
[prev_token, curr_token] = tokens.slice(index - 1, index + 1)
{line, column} = prev_token.loc.end
process.stderr.write(
"[Error] line #{line}, column: #{1 + column}: "+
"Expected ',' or ';' after #{to_string prev_token.value}, "+
"but received #{to_string curr_token.value}\n")
process.exit(1)
transition:
identifier: () -> root.transition.variable_declaration()
terminator: () -> root
separator: () -> root.transition.variable_declaration()
terminator: () -> root
lint = (tokens) ->
state = root
index = 0
prev_token = null
while index < tokens.length
token = tokens[index]
if state.is_valid(token)
state = state.transition[state.next_label token]()
else
state.handle_error(tokens, index)
prev_token = token
index += 1
text = '''
var a = 6;
var b = 7
console.log(a * b);
'''
tokens = esprima.tokenize(text, loc: true)
lint tokens
关于javascript - 如何检测分号是否用于终止 Esprima 生成的 Mozilla 解析器 AST 中的表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23413531/
如果我终止应用程序,我在尝试保持我的功能运行时卡住了。 是否可以在应用程序未运行时保持核心位置(地理围栏/地理定位)和核心蓝牙运行?如果可能如何解决我的问题?我已经检查了背景模式,并实现了核心定位方法
该程序要求用户输入一个数字,然后从列表中返回详细信息。我该怎么做? do { Scanner in = new Scanner(System.in);
我正在开发一个内部分发的 iOS 应用程序(即,没有应用程序商店),我希望能够以恒定的 10 分钟间隔报告设备的位置。 无论如何,我在我的 plist 中包含了 location 作为字段 UIBac
我的 mongodb 服务器突然收到信号 15(终止)。我不知道为什么 mongodb 崩溃了。以下是日志消息。 Mon Jun 27 07:33:31.701 [signalProcessingTh
我按顺序运行了一堆malloc,并且每次都检查以确保它是成功的。像这样: typedef struct { int *aray; char *string; } mystruct; m
这个问题已经有答案了: How to stop a running pthread thread? (4 个回答) 已关闭 8 年前。 可以使用 pthread_join() 停止线程。但让我们想象一
#include #include #include struct node{ char data; int p; struct node *ptr; }; struct node *st
这个问题已经有答案了: Why should I use a semicolon after every function in javascript? (9 个回答) 已关闭 8 年前。 好吧,我问
我有一个启动多个工作线程的函数。每个工作线程都由一个对象封装,该对象的析构函数将尝试加入线程,即调用if (thrd_.joinable()) thrd_.join();。但是,每个 worker 必
我正在实现一个应用程序,当用户摇动手机时,该应用程序会监听并采取行动。 所以我实现了以下服务: public class ShakeMonitorService extends Service {
我在使用 Xcode 时遇到问题,其中弹出错误“Source Kit Service Terminated”,并且所有语法突出显示和代码完成在 Swift 中都消失了。我怎样才能解决这个问题? 这是一
我想为我的控制台应用程序安全退出,该应用程序将使用单声道在 linux 上运行,但我找不到解决方案来检测信号是否发送到它或用户是否按下了 ctrl+c。 在 Windows 上有内核函数 SetCon
关键: pthread_cancel函数发送终止信号pthread_setcancelstate函数设置终止方式pthread_testcancel函数取消线程(另一功能是:设置取消点) 1 线程取消
下面的程序在不同的选项级别下有不同的行为。当我用 -O3 编译它时,它永远不会终止。当我用 -O0 编译它时,它总是很快就会终止。 #include #include void *f(void *
我有 3 个节点的 K8S 集群,我创建了 3 个副本 pod,应用程序 app1 在所有 pod 上运行,我通过运行 service yaml 文件建立了服务,我可以看到通过运行 kubectl g
我打算使用 nginx 来代理 websocket。在执行 nginx reload/HUP 时,我知道 nginx 等待旧的工作进程停止处理所有请求。然而,在 websocket 连接中,这可能不会
在 Ubuntu 9.10 上使用 PVM 3.4.5-12(使用 apt-get 时的 PVM 包) 添加主机后程序终止。 laptop> pvm pvm> add bowtie-slave add
我编写了一个应用程序来从 iPhone 录制视频。它工作正常,但有一个大问题。当 AVCaptureSession 开始运行并且用户尝试从其库(iPod)播放音频时。此操作将使 AVCaptureSe
我将如何使用NSRunningApplication?我有与启动应用程序相反的东西: [[NSWorkspace sharedWorkspace] launchApplication:appName]
我正在使用 NSTask 执行一系列长时间运行的命令,如下所示: commandToRun = @"command 1;command2"; NSArray *arguments = [NSArray
我是一名优秀的程序员,十分优秀!