Merge pull request #31 from ValKmjolnir/develop
📝 update docs and makefile
This commit is contained in:
commit
d108e40e22
80
README.md
80
README.md
|
@ -21,6 +21,7 @@
|
|||
* [__Difference__](#difference-between-andys-and-this-interpreter)
|
||||
* [__Trace Back Info__](#trace-back-info)
|
||||
* [__Debugger__](#debugger)
|
||||
* [__REPL__](#repl)
|
||||
|
||||
__Contact us if having great ideas to share!__
|
||||
|
||||
|
@ -613,19 +614,24 @@ that is really inconvenient.
|
|||
|
||||
Luckily, we have developed some useful native-functions to help you add modules that created by you.
|
||||
|
||||
After 2021/12/3, there are some new functions added to `lib.nas`:
|
||||
Functions used to load dynamic libraries are added to `std/dylib.nas`:
|
||||
|
||||
```javascript
|
||||
var dylib={
|
||||
dlopen: func(libname){
|
||||
...
|
||||
},
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(ptr,args...){return __dlcallv},
|
||||
limitcall: func(arg_size=0){
|
||||
...
|
||||
}
|
||||
};
|
||||
var dlopen = func(libname) {
|
||||
...
|
||||
}
|
||||
|
||||
var dlclose = func(lib) {
|
||||
...
|
||||
}
|
||||
|
||||
var dlcall = func(ptr, args...) {
|
||||
...
|
||||
}
|
||||
|
||||
var limitcall = func(arg_size = 0) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
As you could see, these functions are used to load dynamic libraries into the nasal runtime and execute.
|
||||
|
@ -636,21 +642,26 @@ First, write a cpp file that you want to generate the dynamic lib, take the `fib
|
|||
```C++
|
||||
// add header file nasal.h to get api
|
||||
#include "nasal.h"
|
||||
double fibonaci(double x){
|
||||
if(x<=2)
|
||||
double fibonaci(double x) {
|
||||
if (x<=2) {
|
||||
return x;
|
||||
}
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
// module functions' parameter list example
|
||||
var fib(var* args,usize size,gc* ngc){
|
||||
var fib(var* args, usize size, gc* ngc) {
|
||||
if (!size) {
|
||||
return nas_err("fib", "lack arguments");
|
||||
}
|
||||
// the arguments are generated into a vm_vec: args
|
||||
// get values from the vector that must be used here
|
||||
var num=args[0];
|
||||
var num = args[0];
|
||||
// if you want your function safer, try this
|
||||
// nas_err will print the error info on screen
|
||||
// and return vm_null for runtime to interrupt
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_fib","\"num\" must be number");
|
||||
if(num.type!=vm_num) {
|
||||
return nas_err("extern_fib", "\"num\" must be number");
|
||||
}
|
||||
// ok, you must know that vm_num now is not managed by gc
|
||||
// if want to return a gc object, use ngc->alloc(type)
|
||||
// usage of gc is the same as adding a native function
|
||||
|
@ -659,9 +670,9 @@ var fib(var* args,usize size,gc* ngc){
|
|||
|
||||
// then put function name and address into this table
|
||||
// make sure the end of the table is {nullptr,nullptr}
|
||||
mod_func func_tbl[]={
|
||||
{"fib",fib},
|
||||
{nullptr,nullptr}
|
||||
module_func_info func_tbl[] = {
|
||||
{"fib", fib},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
// must write this function, this will help nasal to
|
||||
|
@ -669,7 +680,7 @@ mod_func func_tbl[]={
|
|||
// the reason why using this way to get function pointer
|
||||
// is because `var` has constructors, which is not compatiable in C
|
||||
// so "extern "C" var fib" may get compilation warnings
|
||||
extern "C" mod_func get(){
|
||||
extern "C" module_func_info* get() {
|
||||
return func_tbl;
|
||||
}
|
||||
```
|
||||
|
@ -693,10 +704,11 @@ Windows(`.dll`):
|
|||
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program:
|
||||
|
||||
```javascript
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dlhandle.fib;
|
||||
for(var i=1;i<30;i+=1)
|
||||
println(dylib.dlcall(fib,i));
|
||||
import.std.dylib;
|
||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib = dlhandle.fib;
|
||||
for(var i = 1; i<30; i+=1)
|
||||
println(dylib.dlcall(fib, i));
|
||||
dylib.dlclose(dlhandle.lib);
|
||||
```
|
||||
|
||||
|
@ -709,11 +721,12 @@ dylib.dlclose(dlhandle.lib);
|
|||
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:
|
||||
|
||||
```javascript
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dlhandle.fib;
|
||||
var invoke=dylib.limitcall(1); # this means the called function has only one parameter
|
||||
for(var i=1;i<30;i+=1)
|
||||
println(invoke(fib,i));
|
||||
import.std.dylib;
|
||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib = dlhandle.fib;
|
||||
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
||||
for(var i = 1; i<30; i+=1)
|
||||
println(invoke(fib, i));
|
||||
dylib.dlclose(dlhandle.lib);
|
||||
```
|
||||
|
||||
|
@ -998,3 +1011,10 @@ vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
|||
```
|
||||
|
||||
</details>
|
||||
|
||||
## REPL
|
||||
|
||||
We added experimental repl interpreter in v11.0.
|
||||
Use this command to use the repl interpreter:
|
||||
|
||||
> nasal -r
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* [__特殊之处__](#与andy解释器的不同之处)
|
||||
* [__堆栈追踪信息__](#堆栈追踪信息)
|
||||
* [__调试器__](#调试器)
|
||||
* [__交互解释器__](#交互解释器)
|
||||
|
||||
__如果有好的意见或建议,欢迎联系我们!__
|
||||
|
||||
|
@ -591,19 +592,24 @@ import("./dirname/dirname/filename.nas");
|
|||
如果只有上文中那种方式来添加你自定义的函数到nasal中,这肯定是非常麻烦的。
|
||||
因此,我们实现了一组实用的内置函数来帮助你添加你自己创建的模块。
|
||||
|
||||
在2021/12/3更新后,我们给`lib.nas`添加了下面的这一批函数:
|
||||
用于加载动态库的函数在`std/dylib.nas`中:
|
||||
|
||||
```javascript
|
||||
var dylib={
|
||||
dlopen: func(libname){
|
||||
...
|
||||
},
|
||||
dlclose: func(lib){return __dlclose; },
|
||||
dlcall: func(ptr,args...){return __dlcallv},
|
||||
limitcall: func(arg_size=0){
|
||||
...
|
||||
}
|
||||
};
|
||||
var dlopen = func(libname) {
|
||||
...
|
||||
}
|
||||
|
||||
var dlclose = func(lib) {
|
||||
...
|
||||
}
|
||||
|
||||
var dlcall = func(ptr, args...) {
|
||||
...
|
||||
}
|
||||
|
||||
var limitcall = func(arg_size = 0) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
这些函数是用来加载动态库的,这样nasal解释器可以根据用户需求灵活加载动态库来执行。让我们看看这些函数该如何使用。
|
||||
|
@ -613,36 +619,41 @@ var dylib={
|
|||
```C++
|
||||
// 这个头文件得加上,因为我们需要拿到nasal的api
|
||||
#include "nasal.h"
|
||||
double fibonaci(double x){
|
||||
if(x<=2)
|
||||
double fibonaci(double x) {
|
||||
if (x<=2) {
|
||||
return x;
|
||||
}
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
}
|
||||
|
||||
// 模块函数的参数列表一律以这个为准
|
||||
var fib(var* args,usize size,gc* ngc){
|
||||
var fib(var* args, usize size, gc* ngc) {
|
||||
if (!size) {
|
||||
return nas_err("fib", "lack arguments");
|
||||
}
|
||||
// 传参会给予一个var指针,指向一个vm_vec的data()
|
||||
var num=args[0];
|
||||
var num = args[0];
|
||||
// 如果你想让这个函数有更强的稳定性,那么一定要进行合法性检查
|
||||
// nas_err会输出错误信息并返回错误类型让虚拟机终止执行
|
||||
if(num.type!=vm_num)
|
||||
return nas_err("extern_fib","\"num\" must be number");
|
||||
if(num.type!=vm_num) {
|
||||
return nas_err("extern_fib", "\"num\" must be number");
|
||||
}
|
||||
// vm_num作为普通的数字类型,不是内存管理的对象,所以无需申请
|
||||
// 如果需要返回内存管理的对象,请使用ngc->alloc(type)
|
||||
return var::num(fibonaci(num.tonum()));
|
||||
}
|
||||
|
||||
// 然后将函数名字和函数地址放到一个表里,一定要记住表尾是{nullptr,nullptr}
|
||||
mod_func func_tbl[]={
|
||||
{"fib",fib},
|
||||
{nullptr,nullptr}
|
||||
module_func_info func_tbl[] = {
|
||||
{"fib", fib},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
// 必须实现这个函数, 这样nasal可以通过字符串名字获得函数指针
|
||||
// 之所以用这种方式来获取函数指针, 是因为`var`是有构造函数的
|
||||
// 有构造函数的类型作为返回值, 和C是不兼容的, 这导致
|
||||
// 类似 "extern "C" var fib" 的写法会得到编译错误
|
||||
extern "C" mod_func get(){
|
||||
extern "C" module_func_info* get() {
|
||||
return func_tbl;
|
||||
}
|
||||
```
|
||||
|
@ -667,10 +678,11 @@ Windows(`.dll`):
|
|||
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
|
||||
|
||||
```javascript
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dlhandle.fib;
|
||||
for(var i=1;i<30;i+=1)
|
||||
println(dylib.dlcall(fib,i));
|
||||
import.std.dylib;
|
||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib = dlhandle.fib;
|
||||
for(var i = 1; i<30; i+=1)
|
||||
println(dylib.dlcall(fib, i));
|
||||
dylib.dlclose(dlhandle.lib);
|
||||
```
|
||||
|
||||
|
@ -683,15 +695,16 @@ dylib.dlclose(dlhandle.lib);
|
|||
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:
|
||||
|
||||
```javascript
|
||||
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib=dlhandle.fib;
|
||||
var invoke=dylib.limitcall(1); # this means the called function has only one parameter
|
||||
for(var i=1;i<30;i+=1)
|
||||
println(invoke(fib,i));
|
||||
import.std.dylib;
|
||||
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
|
||||
var fib = dlhandle.fib;
|
||||
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
|
||||
for(var i = 1; i<30; i+=1)
|
||||
println(invoke(fib, i));
|
||||
dylib.dlclose(dlhandle.lib);
|
||||
```
|
||||
|
||||
如果接下来你看到了这个运行结果,恭喜你!
|
||||
如果得到如下运行结果,恭喜你!
|
||||
|
||||
```bash
|
||||
./nasal a.nas
|
||||
|
@ -963,3 +976,9 @@ vm stack (0x7fffd0259138 <sp+65>, limit 10, total 7)
|
|||
```
|
||||
|
||||
</details>
|
||||
|
||||
## 交互解释器
|
||||
|
||||
v11.0 版本新增了交互式解释器 (REPL),使用如下命令开启:
|
||||
|
||||
> nasal -r
|
||||
|
|
13
makefile
13
makefile
|
@ -1,12 +1,11 @@
|
|||
STD=c++17
|
||||
OS := $(shell uname)
|
||||
STD = c++17
|
||||
OS = $(shell uname)
|
||||
ifeq ($(OS), Darwin)
|
||||
CXXFLAGS=-std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15
|
||||
CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC -mmacosx-version-min=10.15
|
||||
else
|
||||
CXXFLAGS=-std=$(STD) -c -O3 -fno-exceptions -fPIC
|
||||
CXXFLAGS = -std=$(STD) -c -O3 -fno-exceptions -fPIC
|
||||
endif
|
||||
CPPFLAGS=-I .
|
||||
|
||||
CPPFLAGS = -I .
|
||||
|
||||
NASAL_HEADER=\
|
||||
src/ast_dumper.h\
|
||||
|
@ -82,7 +81,7 @@ build/main.o: $(NASAL_HEADER) src/main.cpp | build
|
|||
build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_misc.cpp -o build/nasal_misc.o
|
||||
|
||||
build/repl.o: src/nasal.h src/repl.h src/repl.cpp | build
|
||||
build/repl.o: $(NASAL_HEADER) src/repl.h src/repl.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/repl.cpp -o build/repl.o
|
||||
|
||||
build/nasal_err.o: src/nasal.h src/repl.h src/nasal_err.h src/nasal_err.cpp | build
|
||||
|
|
|
@ -15,7 +15,7 @@ double fibonaci(double x) {
|
|||
|
||||
var fib(var* args, usize size, gc* ngc) {
|
||||
if (!size) {
|
||||
return nas_err("fib","lack arguments");
|
||||
return nas_err("fib", "lack arguments");
|
||||
}
|
||||
var num = args[0];
|
||||
return var::num(fibonaci(num.tonum()));
|
||||
|
|
|
@ -6,11 +6,12 @@ dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll
|
|||
used_header = ../src/nasal.h ../src/nasal_gc.h
|
||||
used_object = ../build/nasal_misc.o ../build/nasal_gc.o
|
||||
|
||||
STD=c++17
|
||||
STD = c++17
|
||||
OS = $(shell uname)
|
||||
ifeq ($(OS), Darwin)
|
||||
CXXFLAGS-std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15
|
||||
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15
|
||||
else
|
||||
CXXFLAGS=-std=$(STD) -c -O3 -fPIC
|
||||
CXXFLAGS = -std=$(STD) -c -O3 -fPIC
|
||||
endif
|
||||
|
||||
all: $(dynamic_libs_so)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
// abbreviation of some useful basic type
|
||||
using i32 = std::int32_t;
|
||||
using i64 = std::int64_t;
|
||||
using u8 = std::uint8_t;
|
||||
|
@ -35,7 +36,8 @@ bool is_powerpc();
|
|||
bool is_superh();
|
||||
|
||||
|
||||
|
||||
// virtual machine stack depth
|
||||
// both global depth and value stack depth
|
||||
const u32 STACK_DEPTH = 4096;
|
||||
|
||||
f64 hex2f(const char*);
|
||||
|
|
|
@ -357,7 +357,7 @@ public:
|
|||
void set_first(expr* node) {first = node;}
|
||||
void add_call(call* node) {calls.push_back(node);}
|
||||
expr* get_first() {return first;}
|
||||
std::vector<call*>& get_calls() {return calls;}
|
||||
auto& get_calls() {return calls;}
|
||||
void accept(ast_visitor*) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -284,9 +284,11 @@ void codegen::func_gen(function* node) {
|
|||
}
|
||||
add_symbol(arg);
|
||||
|
||||
in_loop_level.push_back(0);
|
||||
// generate code block
|
||||
in_foreach_loop_level.push_back(0);
|
||||
block_gen(block);
|
||||
in_loop_level.pop_back();
|
||||
in_foreach_loop_level.pop_back();
|
||||
|
||||
code[lsize].num = local.back().size();
|
||||
if (local.back().size()>=STACK_DEPTH) {
|
||||
die("too many local variants: " +
|
||||
|
@ -771,6 +773,7 @@ void codegen::cond_gen(condition_expr* node) {
|
|||
void codegen::loop_gen(expr* node) {
|
||||
continue_ptr.push_front({});
|
||||
break_ptr.push_front({});
|
||||
|
||||
switch(node->get_type()) {
|
||||
case expr_type::ast_while: while_gen((while_expr*)node); break;
|
||||
case expr_type::ast_for: for_gen((for_expr*)node); break;
|
||||
|
@ -846,9 +849,9 @@ void codegen::forei_gen(forei_expr* node) {
|
|||
}
|
||||
|
||||
// generate code block
|
||||
++in_loop_level.back();
|
||||
++in_foreach_loop_level.back();
|
||||
block_gen(node->get_code_block());
|
||||
--in_loop_level.back();
|
||||
--in_foreach_loop_level.back();
|
||||
|
||||
// jump to loop begin
|
||||
emit(op_jmp, loop_begin, node->get_location());
|
||||
|
@ -1207,7 +1210,7 @@ void codegen::block_gen(code_block* node) {
|
|||
}
|
||||
|
||||
void codegen::ret_gen(return_expr* node) {
|
||||
for(u32 i = 0; i<in_loop_level.back(); ++i) {
|
||||
for(u32 i = 0; i<in_foreach_loop_level.back(); ++i) {
|
||||
emit(op_pop, 0, node->get_location());
|
||||
emit(op_pop, 0, node->get_location());
|
||||
}
|
||||
|
@ -1220,7 +1223,7 @@ const error& codegen::compile(parse& parse, linker& import, bool repl_flag) {
|
|||
init_file_map(import.get_file_list());
|
||||
need_repl_output = repl_flag;
|
||||
|
||||
in_loop_level.push_back(0);
|
||||
in_foreach_loop_level.push_back(0);
|
||||
|
||||
// add special symbol globals, which is a hash stores all global variables
|
||||
add_symbol("globals");
|
||||
|
|
|
@ -34,7 +34,7 @@ class codegen {
|
|||
private:
|
||||
error err;
|
||||
|
||||
//
|
||||
// repl output flag, will generate op_repl to output stack top value if true
|
||||
bool need_repl_output;
|
||||
|
||||
// file mapper for file -> index
|
||||
|
@ -42,7 +42,7 @@ private:
|
|||
void init_file_map(const std::vector<std::string>&);
|
||||
|
||||
// used for generate pop in return expression
|
||||
std::vector<u32> in_loop_level;
|
||||
std::vector<u32> in_foreach_loop_level;
|
||||
|
||||
// constant numbers and strings
|
||||
std::unordered_map<f64, u32> const_number_map;
|
||||
|
|
|
@ -297,7 +297,8 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
|||
auto def = new definition_expr(block->get_location());
|
||||
def->set_identifier(new identifier(
|
||||
block->get_location(),
|
||||
generate_module_name(block->get_location().file)));
|
||||
generate_module_name(block->get_location().file)
|
||||
));
|
||||
|
||||
auto call = new call_expr(block->get_location());
|
||||
auto func = new function(block->get_location());
|
||||
|
@ -310,33 +311,44 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
|||
return def;
|
||||
}
|
||||
|
||||
code_block* linker::load(code_block* root, u16 fileindex) {
|
||||
code_block* linker::load(code_block* program_root, u16 fileindex) {
|
||||
auto tree = new code_block({0, 0, 0, 0, files[fileindex]});
|
||||
// load library, this ast will be linked with root directly
|
||||
// so no namespace is generated
|
||||
// so no extra namespace is generated
|
||||
if (!lib_loaded) {
|
||||
auto tmp = import_nasal_lib();
|
||||
link(tree, tmp);
|
||||
delete tmp;
|
||||
auto nasal_lib_code_block = import_nasal_lib();
|
||||
// insert nasal lib code to the back of tree
|
||||
link(tree, nasal_lib_code_block);
|
||||
delete nasal_lib_code_block;
|
||||
lib_loaded = true;
|
||||
}
|
||||
|
||||
// load imported modules
|
||||
for(auto i : root->get_expressions()) {
|
||||
if (!import_check(i)) {
|
||||
for(auto& import_ast_node : program_root->get_expressions()) {
|
||||
if (!import_check(import_ast_node)) {
|
||||
break;
|
||||
}
|
||||
auto tmp = import_regular_file((call_expr*)i);
|
||||
tree->add_expression(generate_module_definition(tmp));
|
||||
auto module_code_block = import_regular_file((call_expr*)import_ast_node);
|
||||
// after importing the regular file as module, delete this node
|
||||
const auto loc = import_ast_node->get_location();
|
||||
delete import_ast_node;
|
||||
// and replace the node with null_expr node
|
||||
import_ast_node = new null_expr(loc);
|
||||
// then we generate a function warping the code block,
|
||||
// and export the necessary global symbols in this code block
|
||||
// by generate a return statement, with a hashmap return value
|
||||
tree->add_expression(generate_module_definition(module_code_block));
|
||||
}
|
||||
// add root to the back of tree
|
||||
link(tree, root);
|
||||
|
||||
// insert program root to the back of tree
|
||||
link(tree, program_root);
|
||||
return tree;
|
||||
}
|
||||
|
||||
const error& linker::link(
|
||||
parse& parse, const std::string& self, bool spath = false) {
|
||||
show_path = spath;
|
||||
// initializing
|
||||
// initializing file map
|
||||
this_file = self;
|
||||
files = {self};
|
||||
module_load_stack = {self};
|
||||
|
|
|
@ -51,7 +51,8 @@ bool lexer::is_calc_opr(char c) {
|
|||
}
|
||||
|
||||
void lexer::skip_note() {
|
||||
// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
|
||||
// avoid note, after this process ptr will point to '\n'
|
||||
// so next loop line counter+1
|
||||
while(++ptr<res.size() && res[ptr]!='\n') {}
|
||||
}
|
||||
|
||||
|
@ -60,7 +61,8 @@ void lexer::err_char() {
|
|||
char c = res[ptr++];
|
||||
err.err("lexer",
|
||||
{line, column-1, line, column, filename},
|
||||
"invalid character 0x"+chrhex(c));
|
||||
"invalid character 0x"+chrhex(c)
|
||||
);
|
||||
++invalid_char;
|
||||
}
|
||||
|
||||
|
@ -125,11 +127,13 @@ std::string lexer::utf8_gen() {
|
|||
}
|
||||
err.err("lexer",
|
||||
{line, column-1, line, column, filename},
|
||||
"invalid utf-8 <"+utf_info+">");
|
||||
"invalid utf-8 <"+utf_info+">"
|
||||
);
|
||||
++invalid_char;
|
||||
}
|
||||
str += tmp;
|
||||
column += 2; // may have some problems because not all the unicode takes 2 space
|
||||
// may have some problems because not all the unicode takes 2 space
|
||||
column += 2;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
@ -149,7 +153,8 @@ token lexer::id_gen() {
|
|||
tok type = get_type(str);
|
||||
return {
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
(type!=tok::null)? type:tok::id, str};
|
||||
(type!=tok::null)? type:tok::id, str
|
||||
};
|
||||
}
|
||||
|
||||
token lexer::num_gen() {
|
||||
|
@ -167,7 +172,8 @@ token lexer::num_gen() {
|
|||
if (str.length()<3) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
"invalid number `"+str+"`"
|
||||
);
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
|
||||
|
@ -185,7 +191,8 @@ token lexer::num_gen() {
|
|||
if (str.length()==2 || erfmt) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
"invalid number `"+str+"`"
|
||||
);
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||
}
|
||||
|
@ -205,7 +212,8 @@ token lexer::num_gen() {
|
|||
column += str.length();
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
"invalid number `"+str+"`"
|
||||
);
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +230,8 @@ token lexer::num_gen() {
|
|||
column += str.length();
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid number `"+str+"`");
|
||||
"invalid number `"+str+"`"
|
||||
);
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +282,8 @@ token lexer::str_gen() {
|
|||
if (ptr++>=res.size()) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"get EOF when generating string");
|
||||
"get EOF when generating string"
|
||||
);
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||
}
|
||||
++column;
|
||||
|
@ -282,7 +292,8 @@ token lexer::str_gen() {
|
|||
if (begin=='`' && str.length()!=1+utf8_hdchk(str[0])) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"\'`\' is used for string including one character");
|
||||
"\'`\' is used for string including one character"
|
||||
);
|
||||
}
|
||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||
}
|
||||
|
@ -296,7 +307,8 @@ token lexer::single_opr() {
|
|||
if (type==tok::null) {
|
||||
err.err("lexer",
|
||||
{begin_line, begin_column, line, column, filename},
|
||||
"invalid operator `"+str+"`");
|
||||
"invalid operator `"+str+"`"
|
||||
);
|
||||
}
|
||||
++ptr;
|
||||
return {{begin_line, begin_column, line, column, filename}, type, str};
|
||||
|
@ -368,8 +380,10 @@ const error& lexer::scan(const std::string& file) {
|
|||
}
|
||||
}
|
||||
if (toks.size()) {
|
||||
// eof token's location is the last token's location
|
||||
toks.push_back({toks.back().loc, tok::eof, "<eof>"});
|
||||
} else {
|
||||
// if token sequence is empty, generate a default location
|
||||
toks.push_back({{line, column, line, column, filename}, tok::eof, "<eof>"});
|
||||
}
|
||||
res = "";
|
||||
|
|
|
@ -159,7 +159,7 @@ f64 dec2f(const char* str) {
|
|||
if (*str) {
|
||||
return nan("");
|
||||
}
|
||||
return ret*std::pow(10,negative*num_pow);
|
||||
return ret*std::pow(10, negative*num_pow);
|
||||
}
|
||||
|
||||
f64 str2num(const char* str) {
|
||||
|
@ -226,7 +226,7 @@ std::string rawstr(const std::string& str, const usize maxlen) {
|
|||
}
|
||||
}
|
||||
if (maxlen && ret.length()>maxlen) {
|
||||
ret = ret.substr(0,maxlen)+"...";
|
||||
ret = ret.substr(0, maxlen)+"...";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -116,7 +116,9 @@ void repl::execute() {
|
|||
runtime.set_allow_repl_output_flag(true);
|
||||
std::cout << "[nasal-repl] Initialization complete.\n\n";
|
||||
|
||||
std::cout << "Nasal REPL interpreter(experimental).\n";
|
||||
// finish initialization, output version info
|
||||
std::cout << "Nasal REPL interpreter version " << __nasver;
|
||||
std::cout << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||
help();
|
||||
|
||||
while(true) {
|
||||
|
|
|
@ -233,4 +233,5 @@ for(var a=0;a<16;a+=1) {
|
|||
}
|
||||
}
|
||||
|
||||
print([0, 1, 2]~[3, 4, 5], "\n");
|
||||
print([0, 1, 2]~[3, 4, 5], "\n");
|
||||
print(num("4.94065645841246544176568792868e-324"), "\n");
|
Loading…
Reference in New Issue