前一日与jindw聊天,谈到了正在研究的JS代码转换。譬如JSA所作的,其实就是一种代码转换。

PIES为了实现namespace(package)的管理,对JavaScript源代码也进行了处理。为了保证效率,所以想方设法只做了最最简单的预处理,也就是对代码段加头加尾,这样只是简单的字符串串接,对于效率是没有影响的。

但是最近在考虑是否有可能支持一些JS2(ES4)的特性,譬如支持let。这就必然需要将let转换为ES3所支持的某种结构(简单的说,在let语句开始的时候,把let的scope之外的同名变量先压栈,然后到了let的scope之外再恢复出来)。

总之这里就涉及到一种代码的transform或preprocessing。所以我在寻找某种轻型的代码解析方式。为此我先要写一些测试用例。

如果要进行JS代码的parse、transform、预处理、代码生成甚或compile等等,就需要考虑到JS的语法。以下是个很不完整的代码片段,parser、lint、preprocessor、transformer等等都需要能正确处理它,才具有实用价值。

function f(test) {
	
	return (test/*
	/* //
	' "
	{ ;
	\*/ && // /* // " ' { ; \
	test &&
	" /* // \
	\" ' \
	{ ;" &&
	' /* // \
	" \' \
	{ ;' &&
	test);
	
}

这个代码包含了多行注释、单行注释、字符串、多行字符串(非ES3标准,但各种引擎都支持)、转义字符等等。

这个代码没有包含的,包括正则和e4x。正则literal(如/^r(eg)ex["'\/].*?$/ig)是个很麻烦的事情,比如考虑除法!所以暂时没有放入测试用例中。e4x也是一个麻烦事情,因为涉及了内插XML,暂时不予考虑。

BTW,代码syntax highlight其实也会用到类似的处置,显然JavaEye的syntax highlight还是存在小小的地方不能辨识的,呵呵。

下面是一个正则表达式,可以匹配最常见的造成解析困难的嵌套结构,包括注释和字符串,但是没有包括前面所说的正则和e4x的xml结构。
/[/]
  • ([\S\s]*?)(?:[*][/]|$)|[/][/](.*)|"((?:\\"|[^"])*)"|'((?:\\'|[^'])*)'/g;

  • 注:如果你看到上面的代码里存在奇怪的东西,那是JavaEye的bbcode解析错误。

    通过这个正则,我们可以过滤一般的JS代码(当然正则和e4x除外)。比如可以把注释都删除,把字符串里的特殊字符替换掉等等。我测试了上面那段人造的代码。然后我拿dojo 0.4.3的314KB的源代码做了测试,完成整个过滤在我的T60笔记本上大概需要0.5秒。

    不过因为还没有处理正则,所以这个方法还不能用于实用。
    评论
    Army 2008-04-13
    唔……发现不少问题呢,以前都没想到过……受教了~慢慢想想去~
    hax 2008-04-12
    To Army:
    jssc2对于引号内的/*会识别为注释,所以我正文中的代码jssc2似乎尚无法正确高亮。jindw应该不会告诉你要分别处理,因为交叉问题是无法分别处理的,必须一揽子解决,或者采用Token解析方式。但是对于高亮这种用途来说,用Tokenizer代价过高,没有必要,恰好适合用我这里所描述的解决方案。代价是,对于少数极端情况会有高亮错误。
    Army 2008-04-11
    这个jindw曾和我说起过,交叉语法时会有问题,正则、字符串和注释中任意两个相互交叉的话有可能出现高亮错误。

    jindw告诉我的是先将它们分开再进行着色,所以我写jssc2的时候就是受到他的启发的~
    hax 2008-04-11
    narcissus是一个完整的parser。所以它要用Tokenizer。这样开销还是相当大的。我其实想找一个用正则来做一种折衷处置的方式。

    不过经过仔细研究,我发现正则literal是一个理论上难以解决的困境。因为是正则literal还是除法,要根据当时所处的语境(syntactic
    grammar contexts)来决定,而不是只依据syntax的。考虑这样一个代码:

    a = 1
    b = 2
    g = 1
    c = a
    /*
    
    */
    /b/g
    


    注意这里c实际为a/b/g(除法)。如果我检测到/b/g时,要回溯到之前的语境(包括跳过之前的注释)才能决定到底这是一个除法还是正则。这相当困难,因为JS中的正则不支持向前回溯。

    不过在实践当中,几乎没有人会写出这样的语句:
    - 跨行的除法
    - 孤立的正则

    所以可以考虑一种稍微严格的做法。目前正在思考中。
    trydofor 2008-04-11
    http://lxr.mozilla.org/mozilla/source/js/narcissus/
    Brendan Eich's narcissus, a JavaScript parser written in JavaScript for the Mozilla project.
    hax 2008-04-10
    注,列表符号(以及正文中的<li>)应该是“[ * ]”(不包含空格)
    hax 2008-04-10
    BTW,在贴这个代码的时候发现一个小bug,即

    /[/]
  • ([\S\s]*?)(?:[*][/]|$)|[/][/](.*)|"((?:\\\\|\\"|[^"])*)"|'((?:\\\\|\\'|[^'])*)'/

  • 存在某种模式的代码,会匹配错误。不知有人能看出来么,呵呵。
    发表评论

    您还没有登录,请登录后发表评论

    hax
    搜索本博客
    存档
    最新评论