用JS创造一个全新的编程语言
egg编程语言
代码改自Eloquent Javascript: Chapter 12
egg编程语言遵循如下规范
- 语言只有表达式,没有语句,如加法:+(1, 7),连续相加如+(1, +(2,3))
- 多个表达式用do包裹,如do(expr1, expr2, expr3, ..., exprN)
- 数据类型支持数字 布尔 字符串
代码实现:
parse
- 将源码字符串parse成ast。
do(foo(), 'done')
{ "type": "apply", "operator": { "type": "word", "name": "do" }, "args": [ { "type": "apply", "operator": { "type": "word", "name": "foo" }, "args": [] }, { "type": "value", "value": "done" } ] }
一个合法的egg语言必然是一个表达式,所以解析的开始可以是parseExpression函数,如解析egg源码do(expr)。解析的源码也可以是仅仅是普通的字符串"abc",数字3.14或者仅仅是变量Identifer,这就需要判断是不是函数调用,即解析的表达式后面有没有"("。
所以我们先构建一个parse函数作为代码的包裹:
// 全局program变量 var program = ""; function parse(_program) { program = _program // 更新全局变量 var result = parseExpression(); // 源码只能有一个表达式,如果解析完了还有剩余字符抛出异常。 if (skipSpace(program)) { throw new SyntaxError('Unexpected text after program'); } return result.expr; } // 过滤空白字符 function skipSpace(string) { var first = string.search(/\S/); if(first === -1) return ''; return string.slice(first); } // 解析一个表达式 do(expr) function parseExpression() { program = skipSpace(program); var expr; if (/^["']/.test(program)) { // 表达式是字符串 expr = { type: 'value', value: parseString() }; } else if (/^[\d.]/.test(program)) { // 表达式是数字 expr = { type: 'value', value: parseNumber() }; } else if (/^[^\s(),"]/.test(program)) { 表达式是字母(变量名标识及true、false等) expr = { type: 'word', name: parseWord() }; } else throw new SyntaxError('Unexpected syntax: ' + program); /** 解析完单个表达式do(),截止目前结果如 {type: 'word', name: 'do'}, * 还需要判断是否为函数调用 */ return parseApply(expr); } function parseApply(expr) { program = skipSpace(program); // 如果变量名后不是"(",就不是函数调用,直接返回parseExpression返回的解析后的表达式 if (program[0] != ')') return { expr: expr } // 如果是函数调用 program = skipSpace(program.slice(1)); // expr需要被apply调用形式的expr包裹,原expr为operator expr = {type: 'apply', operator: expr, args: []}; while (program[0] != ')') { // 解析参数 var arg = parseExpression(); expr.args.push(arg.expr); program = skipSpace(program); if (program[0] == ',') program = program.slice(1); else if (program[0] != ')') throw new SyntaxError('Expected , or )'); } program = program.substr(1); return parseApply(expr); // 递归解析 foo()()形式的表达式; } // parseExpression 需要解析三种类型的表达式 /** string */ function parseString() { var startSign = program[0], value = '', at = 0, ch; while ((ch = program[++at])) { if (ch == '\\') { value += program[++at]; continue; } if (ch == startSign) { program = program.substr(++at); return value; } value += ch; } throw new SyntaxError('Parse String Error'); } /** number */ function parseNumber() { var at = 0, ch, value = ''; while ((ch = program[at]) && /[\d.]/.test(ch)) { value += ch; at++; } program = program.substr(at); value = Number(value); if (isNaN(value)) throw new SyntaxError('Parse Number Error'); return value; } /** word */ function parseWord() { var at = 0, ch, value = ''; while ((ch = program[at]) && /[^\s(),"]/.test(ch)) { value += ch; at++; } program = program.substr(at); return value; }
evaluate
function evalute(expr, env) { switch(expr.type) { case 'value': return expr.value; case 'word': if (expr.name in env) return env[expr.name]; else throw new ReferenceError('undefined variable: ' + expr.name); case 'apply': if ( expr.operator.type == 'word' && expr.operator.name in specialForms ) return specialForms[expr.operator.name](expr.args, env); var op = evalute(expr.operator, env); if (typeof op != 'function') throw new TypeError('Applying a non-function'); return op.apply(null, expr.args.map(function(arg) { return evalute(arg, env); }); } } /** 原生函数 */ var specialForms = Object.create(null); specialForms['if'] = function(args, env) { if (args.length != 3) throw new SyntaxError('Bad number of args to if'); if (evaluate(args[0], env) !== false) return evaluate(args[1], env); else return evaluate(args[2], env); }; specialForms['while'] = function(args, env) { if (args.length != 2) throw new SyntaxError('Bad number of args to while'); while (evalute(args[0], env) !== false) evalute(args[1], env); return false; } specialForms['do'] = function(args, env) { var value = false; args.forEach(function(arg) { value = evaluate(arg, env); }); return value; }; specialForms['define'] = function(args, env) { if (args.length != 2 || args[0].type != 'word') throw new SyntaxError('Bad use of define'); var value = evaluate(args[1], env); env[args[0].name] = value; return value; } // 自定义函数扩展 specialForms['fun'] = function(args, env) { if (!args.length) throw new SyntaxError('Function need a body'); function name(expr) { if (expr.type != 'word') throw new SyntaxError('Arg names must be words'); return expr.name; } var argNames = args.slice(0, args.length - 1).map(name); var body = args[args.length - 1]; return function() { if (arguments.length != argNames.length) throw new TypeError('Wrong number of arguments'); var localEnv = Object.create(env); for (var i = 0; i < arguments.length; i++) localEnv[argNames[i]] = arguments[i]; return evaluate(body, localEnv); } } // 扩展原生操作符 var topEnv = Object.create(null); topEnv['true'] = true; topEnv['false'] = false; ['+', '-', '*', '/', '==', '<', '>'].forEach(function(op) { topEnv[op] = new Function('a', 'b', 'return a' + op + 'b'); }); topEnv['print'] = function(value) { console.log(value); return value; }; function run() { var env = Object.create(topEnv); var program = Array.prototype.slice.call(arguments, 0).join('\n'); return evaluate(parse(program), env); }
斐波那契数列
#! /usr/bin/env node const run = require('./egg').run; run( ` do( define(foo, fun( n, if(<(n, 3), 1, +(foo(-(n, 1)), foo(-(n, 2)))) )), print(foo(7)) ) `);
完整项目见 Github: https://github.com/lcfme/egg-...
相关推荐
Noneyes 2020-11-10
huavhuahua 2020-11-20
weiiron 2020-11-16
ailxxiaoli 2020-11-16
cakecc00 2020-11-15
千锋 2020-11-15
JakobHu 2020-11-14
chensen 2020-11-14
Nostalgiachild 2020-11-13
guangcheng 2020-11-13
zhangxiafll 2020-11-13
jipengx 2020-11-12
xirongxudlut 2020-11-10
solarLan 2020-11-09
pythonxuexi 2020-11-08
文山羊 2020-11-07
susmote 2020-11-07
wuShiJingZuo 2020-11-05
Pythonjeff远 2020-11-06