javascript - 扩展 Javascript 语法以添加输入

标签 javascript sweet.js esprima

我想扩展 javascript 以添加自定义类型检查。

例如

function test(welcome:string, num:integer:non-zero) {
   console.log(welcome + num)
}

它将编译成:

function test(welcome, num) {
    if(Object.prototype.toString.call(welcome) !== "[object String]") {
        throw new Error('welcome must be a string')
    }

    if (!Number.isInteger(num)) {
        throw new Error('num must be an integer')
    }

    console.log(welcome + num)
}

最直接的方法是什么?

到目前为止我已经看过:

  • sweet.js(在线文档看起来已经过时,因为我认为它正在经历某种内部重写)
  • esprima 和 escodegen(不知道从哪里开始)
  • 使用正则表达式手动解析

最佳答案

在评估了所有不同的选项之后,使用 sweet.js 似乎是最好的解决方案。开始工作仍然相当困难(而且我可能以错误的方式做事),但以防万一有人想做类似的事情,这就是我的解决方案。

    'use strict'

    syntax function = function(ctx) {
        let funcName   = ctx.next().value;
        let funcParams = ctx.next().value;
        let funcBody   = ctx.next().value;

        //produce the normal params array
        var normalParams = produceNormalParams(funcParams)

        //produce the checks
        var paramChecks = produceParamChecks(funcParams)

        //produce the original funcBody code

        //put them together as the final result

        var params = ctx.contextify(funcParams)

        var paramsArray = []
        for (let stx of params) {
            paramsArray.push(stx)
        }

        var inner = #``
        var innerStuff = ctx.contextify(funcBody)
        for (let item of innerStuff) {
            inner = inner.concat(#`${item}`)
        }

        var result = #`function ${funcName} ${normalParams} {
            ${paramChecks}
            ${inner}
        }`

        return result

        function extractParamsAndParamChecks(paramsToken) {
            var paramsContext = ctx.contextify(paramsToken)

            //extracts the actual parameters
            var paramsArray = []
            var i = 0;
            var firstItembyComma = true
            for (let paramItem of paramsContext) {
                if (firstItembyComma) {
                    paramsArray.push({
                        param: paramItem,
                        checks: []
                    })
                    firstItembyComma = false
                }

                if (paramItem.value.token.value === ',') {
                    firstItembyComma = true
                    i++
                } else {
                    paramsArray[i].checks.push(paramItem.value.token.value)
                }
            }

            for (var i = 0; i < paramsArray.length; i++) {
                var checks = paramsArray[i].checks.join('').split(':')
                checks.splice(0, 1)
                paramsArray[i].checks = checks
            }

            return paramsArray
        }

        function produceNormalParams(paramsToken) {
            var paramsArray = extractParamsAndParamChecks(paramsToken)

            //Produces the final params #string
            var inner = #``
            var first = true
            for (let item of paramsArray) {
                if (first === true) {
                    inner = inner.concat(#`${item.param}`)
                } else {
                    inner = inner.concat(#`,${item.param}`)
                }
            }
            return #`(${inner})`
        }

        function produceParamChecks(paramsToken) {
            var paramsArray = extractParamsAndParamChecks(paramsToken)

            var result = #``
            for (let paramObject of paramsArray) {
                var tests = produceChecks(paramObject)
                result = result.concat(#`${tests}`)
            }
            return result
        }

        function produceChecks(paramObject) {
            var paramToken = paramObject.param
            var itemType   = paramObject.checks[0]
            var checks     = paramObject.checks

            if (itemType === undefined) return #``

            if (itemType === 'array') {
                return #`if (Object.prototype.toString.call(${paramToken}) !== "[object Array]") throw new Error('Must be array:' + ${paramToken})`
             else {
                throw new Error('item type not recognised: ' + itemType)
            }
        }
    }

关于javascript - 扩展 Javascript 语法以添加输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43625743/

相关文章:

javascript - 等待未在 esprima 4.0.1 中解析

javascript - 调用方法时出现异常 'Mongol_verifyDoc' ReferenceError : Match is not defined

Javascript - 如果是异步情况

javascript - 我需要找到基于prototype.js的滑出选项卡?

javascript - 将任意字符串插入 sweet.js 输出

javascript - 无法使用 Esprima/Acorn : unexpected token '(' 解析函数

javascript - 类型错误 : Cannot read property '0' of null at SelectedDateService. ngOnInit

sweet.js - 是否可以创建一个 sweetjs 宏,使 JavaScript 中的多行字符串成为可能?

javascript - sweet.js 如何将函数语句与中缀匹配

javascript - 从 ARROW 函数 (es6) 到 ES5