diff --git a/README.md b/README.md index be5159d..5d5619c 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ \_\ \/ \__,_|___/\__,_|_| ``` -![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) -![GitHub release (latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) +![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) +![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) ![in dev](https://img.shields.io/badge/dev-v10.0-blue?style=flat-square&logo=github) [![license](https://img.shields.io/badge/license-MIT-green?style=flat-square&logo=github)](./LICENSE) @@ -20,20 +20,7 @@ * [__Introduction__](#introduction) * [__Compile__](#how-to-compile) * [__Usage__](#how-to-use) -* [__Tutorial__](#tutorial)
more - * [basic value type](#basic-value-type) - * [operators](#operators) - * [definition](#definition) - * [multi-assignment](#multi-assignment) - * [conditional expression](#conditional-expression) - * [loop](#loop) - * [subvec](#subvec) - * [special function call](#special-function-call) - * [lambda](#lambda) - * [closure](#closure) - * [trait](#trait) - * [native functions](#native-functions) - * [modules](#modulesfor-library-developers) +* [__Tutorial__](#tutorial) * [__Release Notes__](./doc/dev.md#release-notes) * [__Development History__](./doc/dev.md) * [__Benchmark__](./doc/benchmark.md) @@ -49,9 +36,9 @@ __Contact us if having great ideas to share!__ __[Nasal](http://wiki.flightgear.org/Nasal_scripting_language)__ is an ECMAscript-like language that used in [FlightGear](https://www.flightgear.org/). -This language is designed by [Andy Ross](https://github.com/andyross). +The designer is [Andy Ross](https://github.com/andyross). -The interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++11`) +This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++11`) without reusing the code in [Andy Ross's nasal interpreter](). But we really appreciate that Andy created this amazing programming language and his interpreter project. @@ -153,7 +140,7 @@ Reading this tutorial will not takes you over 15 minutes. __If you have learnt C/C++/Javascript before, this will take less time.__ You could totally use it after reading this simple tutorial: -### __basic value type__ +
basic value type __`vm_none`__ is error type. This type is used to interrupt the execution of virtual machine and will not be created by user program. @@ -168,11 +155,9 @@ __`vm_num`__ has 3 formats: `dec`, `hex` and `oct`. Using IEEE754 `double` to st ```javascript # this language use '#' to write notes -var n=1; # dec var n=2.71828; # dec var n=2.147e16; # dec var n=1e-10; # dec -var n=0x7fffffff; # hex var n=0xAA55; # hex var n=0o170001; # oct ``` @@ -183,9 +168,7 @@ __`vm_str`__ has 3 formats. The third one is used to declare a character. var s='str'; var s="another string"; var s=`c`; - # some special characters is allowed in this language: - '\a'; '\b'; '\e'; '\f'; '\n'; '\r'; '\t'; '\v'; '\0'; '\\'; '\?'; '\''; @@ -196,13 +179,7 @@ __`vm_vec`__ has unlimited length and can store all types of values. ```javascript var vec=[]; -var vec=[ - 0, - nil, - {}, - [], - func(){return 0;} -]; +var vec=[0,nil,{},[],func(){return 0}]; append(vec,0,1,2); ``` @@ -212,10 +189,9 @@ __`vm_hash`__ is a hashmap(or like a dict in `python`) that stores values with s var hash={ member1:nil, member2:"str", - 'member3':'member\'s name can also be a string constant', - function:func(){ - var a=me.member2~me.member3; - return a; + "member3":"member\'s name can also be a string constant", + funct:func(){ + return me.member2~me.member3; } }; ``` @@ -223,14 +199,10 @@ var hash={ __`vm_func`__ is a function type (in fact it is lambda). ```javascript -var f=func(x,y,z){ - return nil; -} -var f=func{ - return 1024; -} -var f=func(x,y,z,default1=1,default2=2){ - return x+y+z+default1+default2; +var f=func(x,y,z){return nil;} +var f=func{return 114514;} +var f=func(x,y,z,deft=1){ + return x+y+z+deft; } var f=func(args...){ var sum=0; @@ -240,30 +212,20 @@ var f=func(args...){ } ``` -__`vm_upval`__ is a special type that used to store upvalues. -This type is only used in `nasal_vm` to make sure closure runs correctly. +__`vm_upval`__ is used to store upvalues, used in __`nasal_vm`__ to make sure closure runs correctly. -__`vm_obj`__ is a special type that stores user data. -This means you could use other complex C/C++ data types in nasal. -This type is used when you are trying to add a new data structure into nasal, -so this type is often created by native-function that programmed in C/C++ by library developers. -You could see how to write your own native-functions below. +__`vm_obj`__ is used to store other complex C/C++ data types. +This type is often created by native-function of nasal. If want to define your own data type, see how to add native-functions by editing this project. -```javascript -var new_obj=func(){ - return __my_obj(); -} -var obj=new_obj(); -``` +
-### __operators__ +
operators Nasal has basic math operators `+` `-` `*` `/` and a special operator `~` that links two strings together. ```javascript -1+2-1*2/1; +1+2-(1+3)*(2+4)/(16-9); 'str1'~'str2'; -(1+2)*(3+4) ``` For conditional expressions, operators `==` `!=` `<` `>` `<=` `>=` are used to compare two values. @@ -287,14 +249,13 @@ Operators `=` `+=` `-=` `*=` `/=` `~=` are used in assignment expressions. ```javascript a=b=c=d=1; -a+=1; -a-=1; -a*=1; -a/=1; +a+=1; a-=1; a*=1; a/=1; a~='string'; ``` -### __definition__ +
+ +
definition ```javascript var a=1; @@ -304,7 +265,9 @@ var (a,b,c)=(0,1,2); (var a,b,c)=(0,1,2); ``` -### __multi-assignment__ +
+ +
multi-assignment The last one is often used to swap two variables. @@ -314,7 +277,9 @@ The last one is often used to swap two variables. (a,b)=(b,a); ``` -### __conditional expression__ +
+ +
conditional expression In nasal there's a new key word `elsif`. It has the same functions as `else if`. @@ -331,14 +296,15 @@ if(1){ } ``` -### __loop__ +
+ +
loop While loop and for loop is simalar to C/C++. ```javascript while(condition) continue; - for(var i=0;i<10;i+=1) break; ``` @@ -359,7 +325,9 @@ foreach(var i;elem) print(i); ``` -### __subvec__ +
+ +
subvec Nasal provides this special syntax to help user generate a new vector by getting values by one index or getting values by indexes in a range from an old vector. If there's only one index in the bracket, then we will get the value directly. @@ -372,7 +340,9 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil]; "hello world"[0]; ``` -### __special function call__ +
+ +
special function call This is of great use but is not very efficient (because hashmap use string as the key to compare). @@ -381,7 +351,9 @@ This is of great use but is not very efficient f(x:0,y:nil,z:[]); ``` -### __lambda__ +
+ +
lambda Also functions have this kind of use: @@ -406,7 +378,9 @@ var fib=func(f){ ); ``` -### __closure__ +
+ +
closure Closure means you could get the variable that is not in the local scope of a function that you called. Here is an example, result is `1`: @@ -434,7 +408,9 @@ var student=func(n,a){ } ``` -### __trait__ +
+ +
trait Also there's another way to OOP, that is `trait`. @@ -514,7 +490,9 @@ You will get this result now: Because `a.get` will set `me=a` in the `trait.get`. Then `b.get` do the `me=b`. So in fact c is `b.get` too after running `var d=b.get`. If you want to use this trick to make the program running more efficiently, you must know this special mechanism. -### __native functions__ +
+ +
native functions and module import This part shows how we add native functions in this nasal interpreter. If you are interested in this part, this may help you. @@ -627,7 +605,9 @@ nas_ref builtin_keys(nas_ref* local,nasal_gc& gc) } ``` -### __modules(for library developers)__ +
+ +
modules(for lib developers) If there is only one way to add your own functions into nasal, that is really inconvenient. @@ -747,6 +727,8 @@ If get this, Congratulations! 832040 ``` +
+ ## __Difference Between Andy's and This Interpreter__ ### 1. must use `var` to define variables @@ -872,6 +854,8 @@ vm stack(0x7fffff539c28, limit 10, total 1): Use command __`-d`__ or __`--detail`__ the trace back info will show more details: +
show trace back info + ```javascript hello [vm] error: error occurred this line @@ -906,6 +890,8 @@ local(0x7ffff42f3d68): 0x00000001 | str | <0x1932480> error occurred t... ``` +
+ ## __Debugger__ We added a debugger in `v8.0`. @@ -945,23 +931,10 @@ This will help you debugging or learning how the vm works: ```javascript source code: - var fib=func(x) - { ---> if(x<2) return x; - return fib(x-1)+fib(x-2); - } - for(var i=0;i<31;i+=1) - print(fib(i),'\n'); + ... next bytecode: - 0x00000518: 02 00 00 00 02 intl 0x2 (test/fib.nas:1) - 0x00000519: 0d 00 00 00 1a para 0x1a ("x") (test/fib.nas:1) - 0x0000051a: 32 00 00 05 2a jmp 0x52a (test/fib.nas:1) ---> 0x0000051b: 39 00 00 00 01 calll 0x1 (test/fib.nas:3) - 0x0000051c: 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3) - 0x0000051d: 34 00 00 05 20 jf 0x520 (test/fib.nas:3) - 0x0000051e: 39 00 00 00 01 calll 0x1 (test/fib.nas:3) - 0x0000051f: 4a 00 00 00 00 ret 0x0 (test/fib.nas:3) + ... vm stack(0x7fffce09e6e8, limit 10, total 7) 0x00000056 | pc | 0x533 0x00000055 | addr | 0x0 diff --git a/doc/README_zh.md b/doc/README_zh.md index fa5c772..2596408 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -8,8 +8,8 @@ \_\ \/ \__,_|___/\__,_|_| ``` -![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) -![GitHub release (latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) +![GitHub code size](https://img.shields.io/github/languages/code-size/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) +![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github) ![in dev](https://img.shields.io/badge/dev-v10.0-blue?style=flat-square&logo=github) [![license](https://img.shields.io/badge/license-MIT-green?style=flat-square&logo=github)](../LICENSE) @@ -20,20 +20,7 @@ * [__简介__](#简介) * [__编译__](#编译) * [__使用方法__](#使用方法) -* [__教程__](#教程)
展开 - * [基本类型](#基本类型) - * [运算符](#运算符) - * [定义变量](#定义变量) - * [多变量赋值](#多变量赋值) - * [条件语句](#条件语句) - * [循环语句](#循环语句) - * [生成子列表](#生成子列表) - * [特殊函数调用语法](#特殊函数调用语法) - * [lambda表达式](#lambda表达式) - * [闭包](#闭包) - * [trait(特性)](#特性) - * [内置函数](#内置函数) - * [模块](#模块开发者教程) +* [__教程__](#教程) * [__发行日志__](../doc/dev_zh.md#发行日志) * [__开发历史__](../doc/dev_zh.md) * [__测试数据__](../doc/benchmark.md) @@ -138,10 +125,10 @@ if(os.platform()=="windows") ## __教程__ -nasal是非常容易上手的,你甚至可以在15分钟之内看完这里的基本教程并且直接开始编写你想要的程序。 +Nasal是非常容易上手的,你甚至可以在15分钟之内看完这里的基本教程并且直接开始编写你想要的程序。 __如果你先前已经是C/C++,javascript选手,那么这个教程几乎可以不用看了……__ 在看完该教程之后,基本上你就完全掌握了这个语言: -### __基本类型__ +
基本类型 __`vm_none`__ 是特殊的错误类型。这个类型用于终止虚拟机的执行,用户是无法申请到这个类型的,该类型只能由字节码虚拟机自己在抛出错误时产生。 @@ -155,11 +142,9 @@ __`vm_num`__ 有三种形式:十进制,十六进制以及八进制。并且该 ```javascript # this language use '#' to write notes -var n=1; # dec var n=2.71828; # dec var n=2.147e16; # dec var n=1e-10; # dec -var n=0x7fffffff; # hex var n=0xAA55; # hex var n=0o170001; # oct ``` @@ -170,9 +155,7 @@ __`vm_str`__ 也有三种不同的格式。第三种只允许包含一个的字 var s='str'; var s="another string"; var s=`c`; - # 该语言也支持一些特别的转义字符: - '\a'; '\b'; '\e'; '\f'; '\n'; '\r'; '\t'; '\v'; '\0'; '\\'; '\?'; '\''; @@ -183,13 +166,7 @@ __`vm_vec`__ 有不受限制的长度并且可以存储所有类型的数据。( ```javascript var vec=[]; -var vec=[ - 0, - nil, - {}, - [], - func(){return 0;} -]; +var vec=[0,nil,{},[],func(){return 0}]; append(vec,0,1,2); ``` @@ -199,10 +176,9 @@ __`vm_hash`__ 使用哈希表(类似于`python`中的字典),通过键值对 var hash={ member1:nil, member2:"str", - 'member3':'member\'s name can also be a string constant', - function:func(){ - var a=me.member2~me.member3; - return a; + "member3":"member\'s name can also be a string constant", + funct:func(){ + return me.member2~me.member3; } }; ``` @@ -210,14 +186,10 @@ var hash={ __`vm_func`__ 函数类型。(实际上在这个语言里函数也是一种lambda表达式) ```javascript -var f=func(x,y,z){ - return nil; -} -var f=func{ - return 1024; -} -var f=func(x,y,z,default1=1,default2=2){ - return x+y+z+default1+default2; +var f=func(x,y,z){return nil;} +var f=func{return 114514;} +var f=func(x,y,z,deft=1){ + return x+y+z+deft; } var f=func(args...){ var sum=0; @@ -227,25 +199,19 @@ var f=func(args...){ } ``` -__`vm_upval`__ 是用于存储闭包数据的特殊类型。这种类型只在`nasal_vm`中使用,用于确保闭包是可以正确使用的。 +__`vm_upval`__ 是存储闭包数据的特殊类型, 在 __`nasal_vm`__ 中使用,用于确保闭包功能正常。 -__`vm_obj`__ 是一种用来存储用户自定义数据的特别类型。这意味着你可以在nasal中使用C/C++的一些复杂数据结构。如果你想为nasal添加一种新的数据结构,那么就可以使用这个类型的数据。这种类型的数据一般由内置函数或者库开发者提供的模块函数生成。 +__`vm_obj`__ 是用来存储C/C++的一些复杂数据结构。这种类型的数据一般由内置函数或者库开发者提供的模块函数生成。如果你想为nasal添加一种新的数据结构, 可以看下文如何通过修改本项目来添加自己的内置函数。 + +
+ +
运算符 + +Nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,这个运算符用于拼接两个字符串。 ```javascript -var new_obj=func(){ - return __my_obj(); -} -var obj=new_obj(); -``` - -### __运算符__ - -nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的运算符 `~`,这个运算符用于拼接两个字符串。 - -```javascript -1+2-1*2/1; +1+2-(1+3)*(2+4)/(16-9); 'str1'~'str2'; -(1+2)*(3+4) ``` 对于条件语句,可以使用`==` `!=` `<` `>` `<=` `>=`来比较两个数据。`and` `or` 有着与C/C++中 `&&` `||`运算符相同的功能,用于连接两个不同的条件语句。 @@ -268,14 +234,13 @@ nasal拥有基本的四种数学运算符 `+` `-` `*` `/`以及一个特别的 ```javascript a=b=c=d=1; -a+=1; -a-=1; -a*=1; -a/=1; +a+=1; a-=1; a*=1; a/=1; a~='string'; ``` -### __定义变量__ +
+ +
定义变量 ```javascript var a=1; @@ -285,7 +250,9 @@ var (a,b,c)=(0,1,2); (var a,b,c)=(0,1,2); ``` -### __多变量赋值__ +
+ +
多变量赋值 最后这个语句通常用于交换两个变量的数据,类似于Python中的操作。 @@ -295,7 +262,9 @@ var (a,b,c)=(0,1,2); (a,b)=(b,a); ``` -### __条件语句__ +
+ +
条件语句 nasal在提供`else if`的同时还有另外一个关键字`elsif`。该关键字与`else if`有相同的功能。 @@ -311,14 +280,15 @@ if(1){ } ``` -### __循环语句__ +
+ +
循环语句 while循环和for循环大体上与C/C++是一致的。 ```javascript while(condition) continue; - for(var i=0;i<10;i+=1) break; ``` @@ -339,7 +309,9 @@ foreach(var i;elem) print(i); ``` -### __生成子列表__ +
+ +
生成子列表(subvec) nasal提供了下面第一句的类似语法来从列表中随机或者按照一个区间获取数据,并且拼接生成一个新的列表。当然如果中括号内只有一个下标的话,你会直接获得这个下标对应的数据而不是一个子列表。如果直接对string使用下标来获取内容的话,会得到对应字符的 __ascii值__。如果你想进一步获得这个字符串,可以尝试使用内置函数`chr()`。 @@ -349,7 +321,9 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil]; "hello world"[0]; ``` -### __特殊函数调用语法__ +
+ +
特殊函数调用语法 这种特别的调用方式有时非常有用,但是切记这种调用方式不是很高效,因为哈希表会使用字符串比对来找到数据存放的位置。 @@ -357,7 +331,9 @@ a[-1,1,0:2,0:,:3,:,nil:8,3:nil,nil:nil]; f(x:0,y:nil,z:[]); ``` -### __lambda表达式__ +
+ +
lambda表达式 正如上文所述,函数有这样一种直接编写函数体并且直接调用的方式: @@ -381,7 +357,9 @@ var fib=func(f){ ); ``` -### __闭包__ +
+ +
闭包 闭包是一种特别的作用域,你可以从这个作用域中获取其保存的所有变量,而这些变量原本不是你当前运行的函数的局部作用域中的。下面这个例子里,结果是`1`: @@ -408,7 +386,9 @@ var student=func(n,a){ } ``` -### __特性__ +
+ +
特性与继承 当然,也有另外一种办法来面向对象编程,那就是利用`trait`。 @@ -485,7 +465,9 @@ println(d()); 因为执行`a.get`时在`trait.get`函数的属性中进行了`me=a`的操作。而`b.get`则执行了`me=b`的操作。所以在运行`var d=b.get`后实际上c也变成`b.get`了。 如果你想要用这种小技巧来让程序运行更高效的话,最好是要知道这里存在这样一个机制。 -### __内置函数__ +
+ +
原生内置函数以及模块导入(import)语法 这个部分对于纯粹的使用者来说是不需要了解的,它将告诉你我们是如何为这个解释器添加新的内置函数的。如果你对于添加自己私人订制的内置函数很感兴趣,那么这个部分可能会帮到你,并且…… @@ -594,7 +576,9 @@ nas_ref builtin_keys(nas_ref* local,nasal_gc& gc) } ``` -### __模块(开发者教程)__ +
+ +
模块(开发者教程) 如果只有上文中那种方式来添加你自定义的函数到nasal中,这肯定是非常麻烦的。因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。 @@ -707,6 +691,8 @@ dylib.dlclose(dlhandle); 832040 ``` +
+ ## __与andy解释器的不同之处__ ### 1. 必须用`var`定义变量 @@ -820,6 +806,8 @@ vm stack(0x7fffff539c28, limit 10, total 1): 使用命令 __`-d`__ 或 __`--detail`__ 后,trace back信息会包含更多的细节内容: +
展开堆栈错误信息 + ```javascript hello [vm] error: error occurred this line @@ -854,6 +842,8 @@ local(0x7ffff42f3d68): 0x00000001 | str | <0x1932480> error occurred t... ``` +
+ ## __调试器__ 在`v8.0`版本中我们添加了调试器。 @@ -892,23 +882,10 @@ vm stack(0x7fffce09e6e8, limit 10, total 0) ```javascript source code: - var fib=func(x) - { ---> if(x<2) return x; - return fib(x-1)+fib(x-2); - } - for(var i=0;i<31;i+=1) - print(fib(i),'\n'); + ... next bytecode: - 0x00000518: 02 00 00 00 02 intl 0x2 (test/fib.nas:1) - 0x00000519: 0d 00 00 00 1a para 0x1a ("x") (test/fib.nas:1) - 0x0000051a: 32 00 00 05 2a jmp 0x52a (test/fib.nas:1) ---> 0x0000051b: 39 00 00 00 01 calll 0x1 (test/fib.nas:3) - 0x0000051c: 2d 00 00 00 03 lessc 0x3 (2) (test/fib.nas:3) - 0x0000051d: 34 00 00 05 20 jf 0x520 (test/fib.nas:3) - 0x0000051e: 39 00 00 00 01 calll 0x1 (test/fib.nas:3) - 0x0000051f: 4a 00 00 00 00 ret 0x0 (test/fib.nas:3) + ... vm stack(0x7fffce09e6e8, limit 10, total 7) 0x00000056 | pc | 0x533 0x00000055 | addr | 0x0