Merge pull request #43 from ValKmjolnir/develop

🎨 rename & file structure change & improve ast/gc dump format
This commit is contained in:
ValK 2024-06-02 22:51:28 +08:00 committed by GitHub
commit 0cf8e3bd23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 1803 additions and 1361 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(nasal VERSION 10.1)
project(nasal VERSION 11.2)
message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
@ -16,10 +16,8 @@ set(CMAKE_BUILD_TYPE "Release")
# build nasal used object
set(NASAL_OBJECT_SOURCE_FILE
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
${CMAKE_SOURCE_DIR}/src/natives/nasal_builtin.cpp
${CMAKE_SOURCE_DIR}/src/cli/cli.cpp
${CMAKE_SOURCE_DIR}/src/natives/builtin.cpp
${CMAKE_SOURCE_DIR}/src/natives/coroutine.cpp
${CMAKE_SOURCE_DIR}/src/natives/fg_props.cpp
${CMAKE_SOURCE_DIR}/src/natives/bits_lib.cpp
@ -29,31 +27,37 @@ set(NASAL_OBJECT_SOURCE_FILE
${CMAKE_SOURCE_DIR}/src/natives/dylib_lib.cpp
${CMAKE_SOURCE_DIR}/src/natives/regex_lib.cpp
${CMAKE_SOURCE_DIR}/src/natives/unix_lib.cpp
${CMAKE_SOURCE_DIR}/src/repl/repl.cpp
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
${CMAKE_SOURCE_DIR}/src/util/util.cpp
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
${CMAKE_SOURCE_DIR}/src/nasal_dbg.cpp
${CMAKE_SOURCE_DIR}/src/nasal_err.cpp
${CMAKE_SOURCE_DIR}/src/nasal_gc.cpp
${CMAKE_SOURCE_DIR}/src/nasal_import.cpp
${CMAKE_SOURCE_DIR}/src/nasal_lexer.cpp
${CMAKE_SOURCE_DIR}/src/nasal_misc.cpp
${CMAKE_SOURCE_DIR}/src/nasal_opcode.cpp
${CMAKE_SOURCE_DIR}/src/nasal_parse.cpp
${CMAKE_SOURCE_DIR}/src/nasal_type.cpp
${CMAKE_SOURCE_DIR}/src/nasal_vm.cpp
${CMAKE_SOURCE_DIR}/src/optimizer.cpp
${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp
${CMAKE_SOURCE_DIR}/src/repl.cpp)
${CMAKE_SOURCE_DIR}/src/symbol_finder.cpp)
add_library(nasal-object STATIC ${NASAL_OBJECT_SOURCE_FILE})
target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
# build nasal
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
target_link_libraries(nasal nasal-object)
# link ldl and lpthread
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(nasal dl)
target_link_libraries(nasal pthread)
endif()
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
# copy nasal from build dir to the outside dir
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
add_custom_command(
TARGET nasal POST_BUILD
@ -67,10 +71,12 @@ endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/module)
set(MODULE_USED_OBJECT_SOURCE_FILE
${CMAKE_SOURCE_DIR}/src/nasal_misc.cpp
${CMAKE_SOURCE_DIR}/src/util/util.cpp
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
${CMAKE_SOURCE_DIR}/src/nasal_type.cpp
${CMAKE_SOURCE_DIR}/src/nasal_gc.cpp)
add_library(module-used-object STATIC ${MODULE_USED_OBJECT_SOURCE_FILE})
target_include_directories(module-used-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
add_library(fib SHARED ${CMAKE_SOURCE_DIR}/module/fib.cpp)
target_include_directories(fib PRIVATE ${CMAKE_SOURCE_DIR}/src)

View File

@ -26,11 +26,9 @@
__Contact us if having great ideas to share!__
* __E-mail__:
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __sidi.liang@gmail.com__ (Sidi)
* __sidi.liang@gmail.com__ (Sidi)
## __Introduction__
@ -117,6 +115,14 @@ if (os.platform()=="windows") {
}
```
Or use `std.runtime.windows.set_utf8_output()`:
```javascript
use std.runtime;
runtime.windows.set_utf8_output();
```
## __Difference Between Andy's and This Interpreter__
![error](./doc/gif/error.gif)
@ -337,9 +343,8 @@ and the debugger will print this:
```javascript
source code:
--> var fib=func(x)
{
if(x<2) return x;
--> var fib = func(x) {
if (x<2) return x;
return fib(x-1)+fib(x-2);
}
for(var i=0;i<31;i+=1)
@ -347,16 +352,16 @@ source code:
next bytecode:
0x000848 4a 00 00 01 callfv 0x1(std/lib.nas:427)
0x000849 3d 00 00 00 pop 0x0(std/lib.nas:427)
0x00084a 07 00 00 00 pnil 0x0(std/lib.nas:423)
0x00084b 56 00 00 00 ret 0x0(std/lib.nas:423)
0x00084c 03 00 00 5e loadg 0x5e(std/lib.nas:423)
--> 0x00084d 0b 00 08 51 newf 0x851(test/fib.nas:1)
0x00084e 02 00 00 03 intl 0x3(test/fib.nas:1)
0x00084f 0d 00 00 08 para 0x8 (x)(test/fib.nas:1)
0x0003a8 07:00 00 00 00 00 00 00 00 pnil 0x0 (std/lib.nas:413)
0x0003a9 56:00 00 00 00 00 00 00 00 ret 0x0 (std/lib.nas:413)
0x0003aa 03:00 00 00 00 00 00 00 56 loadg 0x56 (std/lib.nas:413)
--> 0x0003ab 0b:00 00 00 00 00 00 03 af newf 0x3af (test/fib.nas:1)
0x0003ac 02:00 00 00 00 00 00 00 03 intl 0x3 (test/fib.nas:1)
0x0003ad 0d:00 00 00 00 00 00 00 22 para 0x22 (x) (test/fib.nas:1)
0x0003ae 3e:00 00 00 00 00 00 03 be jmp 0x3be (test/fib.nas:1)
0x0003af 45:00 00 00 00 00 00 00 01 calll 0x1 (test/fib.nas:2)
stack (0x55ccd0a1b9d0, limit 10, total 0)
vm stack (0x7fca7e9f1010, limit 16, total 0)
>>
```
@ -371,9 +376,8 @@ This will help you debugging or learning how the vm works:
```javascript
source code:
var fib=func(x)
{
--> if(x<2) return x;
var fib = func(x) {
--> if (x<2) return x;
return fib(x-1)+fib(x-2);
}
for(var i=0;i<31;i+=1)
@ -381,24 +385,24 @@ source code:
next bytecode:
0x000850 3e 00 08 60 jmp 0x860(test/fib.nas:1)
--> 0x000851 45 00 00 01 calll 0x1(test/fib.nas:3)
0x000852 39 00 00 07 lessc 0x7 (2)(test/fib.nas:3)
0x000853 40 00 08 56 jf 0x856(test/fib.nas:3)
0x000854 45 00 00 01 calll 0x1(test/fib.nas:3)
0x000855 56 00 00 00 ret 0x0(test/fib.nas:3)
0x000856 44 00 00 5f callg 0x5f(test/fib.nas:4)
0x000857 45 00 00 01 calll 0x1(test/fib.nas:4)
0x0003a8 07:00 00 00 00 00 00 00 00 pnil 0x0 (std/lib.nas:413)
0x0003a9 56:00 00 00 00 00 00 00 00 ret 0x0 (std/lib.nas:413)
0x0003aa 03:00 00 00 00 00 00 00 56 loadg 0x56 (std/lib.nas:413)
0x0003ab 0b:00 00 00 00 00 00 03 af newf 0x3af (test/fib.nas:1)
0x0003ac 02:00 00 00 00 00 00 00 03 intl 0x3 (test/fib.nas:1)
0x0003ad 0d:00 00 00 00 00 00 00 22 para 0x22 (x) (test/fib.nas:1)
0x0003ae 3e:00 00 00 00 00 00 03 be jmp 0x3be (test/fib.nas:1)
--> 0x0003af 45:00 00 00 00 00 00 00 01 calll 0x1 (test/fib.nas:2)
stack (0x55ccd0a1b9d0, limit 10, total 8)
0x000007 | pc | 0x869
vm stack (0x7fca7e9f1010, limit 16, total 8)
0x000007 | pc | 0x3c7
0x000006 | addr | 0x0
0x000005 | nil |
0x000004 | nil |
0x000003 | num | 0
0x000002 | nil |
0x000001 | nil |
0x000000 | func | <0x55ccd0a58fa0> entry:0x487
0x000000 | func | <0x5573f66ef5f0> func(elems...) {..}
>>
```

View File

@ -26,11 +26,9 @@
__如果有好的意见或建议欢迎联系我们!__
* __E-mail__:
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __lhk101lhk101@qq.com__ (ValKmjolnir)
* __1467329765@qq.com__(Sidi762)
* __sidi.liang@gmail.com__ (Sidi)
## __简介__
@ -103,7 +101,7 @@ Windows 平台的预览版解释器现在还没配置相关流水线,
![usage](../doc/gif/help.gif)
如果你是 `Windows` 用户且想正常输出unicode在nasal代码里写这个来开启unicode代码页:
如果你是 `Windows` 用户且想正常输出 unicode可以这样开启 unicode 代码页:
```javascript
if (os.platform()=="windows") {
@ -111,6 +109,14 @@ if (os.platform()=="windows") {
}
```
或者使用 `std.runtime.windows.set_utf8_output()`:
```javascript
use std.runtime;
runtime.windows.set_utf8_output();
```
## __与andy解释器的不同之处__
![error](../doc/gif/error.gif)
@ -322,9 +328,8 @@ local (0x55dcb5b43190 <+7>)
```javascript
source code:
--> var fib=func(x)
{
if(x<2) return x;
--> var fib = func(x) {
if (x<2) return x;
return fib(x-1)+fib(x-2);
}
for(var i=0;i<31;i+=1)
@ -332,16 +337,16 @@ source code:
next bytecode:
0x000848 4a 00 00 01 callfv 0x1(std/lib.nas:427)
0x000849 3d 00 00 00 pop 0x0(std/lib.nas:427)
0x00084a 07 00 00 00 pnil 0x0(std/lib.nas:423)
0x00084b 56 00 00 00 ret 0x0(std/lib.nas:423)
0x00084c 03 00 00 5e loadg 0x5e(std/lib.nas:423)
--> 0x00084d 0b 00 08 51 newf 0x851(test/fib.nas:1)
0x00084e 02 00 00 03 intl 0x3(test/fib.nas:1)
0x00084f 0d 00 00 08 para 0x8 (x)(test/fib.nas:1)
0x0003a8 07:00 00 00 00 00 00 00 00 pnil 0x0 (std/lib.nas:413)
0x0003a9 56:00 00 00 00 00 00 00 00 ret 0x0 (std/lib.nas:413)
0x0003aa 03:00 00 00 00 00 00 00 56 loadg 0x56 (std/lib.nas:413)
--> 0x0003ab 0b:00 00 00 00 00 00 03 af newf 0x3af (test/fib.nas:1)
0x0003ac 02:00 00 00 00 00 00 00 03 intl 0x3 (test/fib.nas:1)
0x0003ad 0d:00 00 00 00 00 00 00 22 para 0x22 (x) (test/fib.nas:1)
0x0003ae 3e:00 00 00 00 00 00 03 be jmp 0x3be (test/fib.nas:1)
0x0003af 45:00 00 00 00 00 00 00 01 calll 0x1 (test/fib.nas:2)
stack (0x55ccd0a1b9d0, limit 10, total 0)
vm stack (0x7fca7e9f1010, limit 16, total 0)
>>
```
@ -356,9 +361,8 @@ stack (0x55ccd0a1b9d0, limit 10, total 0)
```javascript
source code:
var fib=func(x)
{
--> if(x<2) return x;
var fib = func(x) {
--> if (x<2) return x;
return fib(x-1)+fib(x-2);
}
for(var i=0;i<31;i+=1)
@ -366,24 +370,24 @@ source code:
next bytecode:
0x000850 3e 00 08 60 jmp 0x860(test/fib.nas:1)
--> 0x000851 45 00 00 01 calll 0x1(test/fib.nas:3)
0x000852 39 00 00 07 lessc 0x7 (2)(test/fib.nas:3)
0x000853 40 00 08 56 jf 0x856(test/fib.nas:3)
0x000854 45 00 00 01 calll 0x1(test/fib.nas:3)
0x000855 56 00 00 00 ret 0x0(test/fib.nas:3)
0x000856 44 00 00 5f callg 0x5f(test/fib.nas:4)
0x000857 45 00 00 01 calll 0x1(test/fib.nas:4)
0x0003a8 07:00 00 00 00 00 00 00 00 pnil 0x0 (std/lib.nas:413)
0x0003a9 56:00 00 00 00 00 00 00 00 ret 0x0 (std/lib.nas:413)
0x0003aa 03:00 00 00 00 00 00 00 56 loadg 0x56 (std/lib.nas:413)
0x0003ab 0b:00 00 00 00 00 00 03 af newf 0x3af (test/fib.nas:1)
0x0003ac 02:00 00 00 00 00 00 00 03 intl 0x3 (test/fib.nas:1)
0x0003ad 0d:00 00 00 00 00 00 00 22 para 0x22 (x) (test/fib.nas:1)
0x0003ae 3e:00 00 00 00 00 00 03 be jmp 0x3be (test/fib.nas:1)
--> 0x0003af 45:00 00 00 00 00 00 00 01 calll 0x1 (test/fib.nas:2)
stack (0x55ccd0a1b9d0, limit 10, total 8)
0x000007 | pc | 0x869
vm stack (0x7fca7e9f1010, limit 16, total 8)
0x000007 | pc | 0x3c7
0x000006 | addr | 0x0
0x000005 | nil |
0x000004 | nil |
0x000003 | num | 0
0x000002 | nil |
0x000001 | nil |
0x000000 | func | <0x55ccd0a58fa0> entry:0x487
0x000000 | func | <0x5573f66ef5f0> func(elems...) {..}
>>
```

View File

@ -13,7 +13,7 @@ NASAL_HEADER = \
src/ast_dumper.h\
src/ast_visitor.h\
src/nasal_ast.h\
src/natives/nasal_builtin.h\
src/natives/builtin.h\
src/nasal_codegen.h\
src/nasal_dbg.h\
src/nasal_err.h\
@ -27,6 +27,7 @@ NASAL_HEADER = \
src/nasal.h\
src/optimizer.h\
src/symbol_finder.h\
src/cli/cli.h\
src/natives/fg_props.h\
src/natives/bits_lib.h\
src/natives/io_lib.h\
@ -35,8 +36,10 @@ NASAL_HEADER = \
src/natives/json_lib.h\
src/natives/unix_lib.h\
src/natives/coroutine.h\
src/repl.h\
src/natives/regex_lib.h
src/natives/regex_lib.h\
src/repl/repl.h\
src/util/fs.h\
src/util/util.h
NASAL_OBJECT = \
build/nasal_err.o\
@ -51,9 +54,8 @@ NASAL_OBJECT = \
build/nasal_opcode.o\
build/symbol_finder.o\
build/nasal_codegen.o\
build/nasal_misc.o\
build/nasal_gc.o\
build/nasal_builtin.o\
build/builtin.o\
build/fg_props.o\
build/io_lib.o\
build/math_lib.o\
@ -64,8 +66,11 @@ NASAL_OBJECT = \
build/nasal_type.o\
build/nasal_vm.o\
build/nasal_dbg.o\
build/repl.o\
build/regex_lib.o\
build/repl.o\
build/cli.o\
build/fs.o\
build/util.o\
build/main.o
@ -86,16 +91,25 @@ build:
build/main.o: $(NASAL_HEADER) src/main.cpp | build
$(CXX) $(CXXFLAGS) src/main.cpp -o build/main.o
build/nasal_misc.o: src/nasal.h src/nasal_misc.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_misc.cpp -o build/nasal_misc.o
build/cli.o: src/cli/cli.h src/cli/cli.cpp | build
$(CXX) $(CXXFLAGS) src/cli/cli.cpp -o build/cli.o
build/repl.o: $(NASAL_HEADER) src/repl.h src/repl.cpp | build
$(CXX) $(CXXFLAGS) src/repl.cpp -o build/repl.o
build/util.o: src/util/util.h src/util/util.cpp | build
$(CXX) $(CXXFLAGS) src/util/util.cpp -o build/util.o
build/nasal_err.o: src/nasal.h src/repl.h src/nasal_err.h src/nasal_err.cpp | build
build/fs.o: src/nasal.h src/util/util.h src/util/fs.h src/util/fs.cpp | build
$(CXX) $(CXXFLAGS) src/util/fs.cpp -o build/fs.o
build/repl.o: $(NASAL_HEADER) src/repl/repl.h src/repl/repl.cpp | build
$(CXX) $(CXXFLAGS) src/repl/repl.cpp -o build/repl.o
build/nasal_err.o: src/nasal.h src/repl/repl.h src/nasal_err.h src/nasal_err.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_err.cpp -o build/nasal_err.o
build/nasal_type.o: src/nasal.h src/nasal_type.h src/nasal_type.cpp | build
build/nasal_type.o:\
src/nasal.h\
src/util/util.h\
src/nasal_type.h src/nasal_type.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_type.cpp -o build/nasal_type.o
build/nasal_gc.o: src/nasal.h src/nasal_type.h src/nasal_gc.h src/nasal_gc.cpp | build
@ -106,12 +120,16 @@ build/nasal_import.o: \
src/nasal_ast.h\
src/nasal_lexer.h\
src/nasal_parse.h\
src/util/util.h\
src/util/fs.h\
src/nasal_import.h src/nasal_import.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_import.cpp -o build/nasal_import.o
build/nasal_lexer.o: \
src/nasal.h\
src/repl.h\
src/repl/repl.h\
src/util/util.h\
src/util/fs.h\
src/nasal_err.h\
src/nasal_lexer.h src/nasal_lexer.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_lexer.cpp -o build/nasal_lexer.o
@ -122,12 +140,14 @@ build/nasal_ast.o: \
src/nasal_ast.h src/nasal_ast.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_ast.cpp -o build/nasal_ast.o
build/nasal_builtin.o: \
build/builtin.o: \
src/nasal.h\
src/nasal_type.h\
src/nasal_gc.h\
src/natives/nasal_builtin.h src/natives/nasal_builtin.cpp | build
$(CXX) $(CXXFLAGS) src/natives/nasal_builtin.cpp -o build/nasal_builtin.o
src/util/util.h\
src/natives/builtin.h\
src/natives/builtin.cpp | build
$(CXX) $(CXXFLAGS) src/natives/builtin.cpp -o build/builtin.o
build/coroutine.o: \
src/nasal.h\
@ -143,7 +163,6 @@ build/bits_lib.o: \
src/natives/bits_lib.h src/natives/bits_lib.cpp | build
$(CXX) $(CXXFLAGS) src/natives/bits_lib.cpp -o build/bits_lib.o
build/math_lib.o: \
src/nasal.h\
src/nasal_type.h\
@ -155,6 +174,7 @@ build/io_lib.o: \
src/nasal.h\
src/nasal_type.h\
src/nasal_gc.h\
src/util/fs.h\
src/natives/io_lib.h src/natives/io_lib.cpp | build
$(CXX) $(CXXFLAGS) src/natives/io_lib.cpp -o build/io_lib.o
@ -169,6 +189,7 @@ build/json_lib.o: \
src/nasal.h\
src/nasal_type.h\
src/nasal_gc.h\
src/util/util.h\
src/natives/json_lib.h src/natives/json_lib.cpp | build
$(CXX) $(CXXFLAGS) src/natives/json_lib.cpp -o build/json_lib.o
@ -198,7 +219,8 @@ build/nasal_codegen.o: $(NASAL_HEADER) src/nasal_codegen.h src/nasal_codegen.cpp
build/nasal_opcode.o: \
src/nasal.h\
src/natives/nasal_builtin.h\
src/natives/builtin.h\
src/util/util.h\
src/nasal_opcode.h src/nasal_opcode.cpp | build
$(CXX) $(CXXFLAGS) src/nasal_opcode.cpp -o build/nasal_opcode.o
@ -207,6 +229,7 @@ build/nasal_parse.o: \
src/nasal_ast.h\
src/nasal_lexer.h\
src/nasal_err.h\
src/util/util.h\
src/nasal_parse.h src/nasal_parse.cpp src/nasal_ast.h | build
$(CXX) $(CXXFLAGS) src/nasal_parse.cpp -o build/nasal_parse.o
@ -238,6 +261,7 @@ build/ast_dumper.o: \
src/nasal_err.h\
src/nasal_ast.h\
src/ast_visitor.h\
src/util/util.h\
src/ast_dumper.h src/ast_dumper.cpp | build
$(CXX) $(CXXFLAGS) src/ast_dumper.cpp -o build/ast_dumper.o
@ -294,5 +318,6 @@ test:nasal
@ ./nasal -e test/trait.nas
@ ./nasal -t -d test/turingmachine.nas
@ ./nasal -d test/wavecollapse.nas
@ ./nasal -d test/wavecity.nas
@ ./nasal test/word_collector.nas test/md5compare.nas
@ ./nasal -t -d test/ycombinator.nas

View File

@ -34,7 +34,8 @@ public:
tcgetattr(0, &init_termios);
new_termios = init_termios;
new_termios.c_lflag &= ~(ICANON|ECHO|ECHONL|ECHOE);
// vmin=0 is nonblock input, but in wsl there is a bug that will block input
// vmin = 0 is nonblock input,
// but in wsl1 there is a bug that will block input
// so we use fcntl to write the nonblock input
new_termios.c_cc[VMIN] = 1;
new_termios.c_cc[VTIME] = 0;

View File

@ -3,8 +3,8 @@
dynamic_libs_so = libfib.so libkey.so libnasock.so libmat.so
dynamic_libs_dll = libfib.dll libkey.dll libnasock.dll libmat.dll
used_header = ../src/nasal.h ../src/nasal_type.h ../src/nasal_gc.h
used_object = ../build/nasal_misc.o ../build/nasal_type.o ../build/nasal_gc.o
used_header = ../src/nasal.h ../src/util/util.h ../src/nasal_type.h ../src/nasal_gc.h
used_object = ../build/util.o ../build/nasal_type.o ../build/nasal_gc.o
STD = c++17

View File

@ -1,4 +1,5 @@
#include "ast_dumper.h"
#include "util/util.h"
#include <iostream>
@ -6,7 +7,7 @@ namespace nasal {
bool ast_dumper::visit_use_stmt(use_stmt* node) {
dump_indent();
std::cout << "use" << format_location(node->get_location());
std::cout << "use" << format_location(node);
push_indent();
for(auto i : node->get_path()) {
if (i==node->get_path().back()) {
@ -20,48 +21,48 @@ bool ast_dumper::visit_use_stmt(use_stmt* node) {
bool ast_dumper::visit_null_expr(null_expr* node) {
dump_indent();
std::cout << "null" << format_location(node->get_location());
std::cout << "null" << format_location(node);
return true;
}
bool ast_dumper::visit_nil_expr(nil_expr* node) {
dump_indent();
std::cout << "nil" << format_location(node->get_location());
std::cout << "nil" << format_location(node);
return true;
}
bool ast_dumper::visit_number_literal(number_literal* node) {
dump_indent();
std::cout << "number " << node->get_number();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_string_literal(string_literal* node) {
dump_indent();
std::cout << "string \"" << rawstr(node->get_content()) << "\"";
std::cout << format_location(node->get_location());
std::cout << "string \"" << util::rawstr(node->get_content()) << "\"";
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_identifier(identifier* node) {
dump_indent();
std::cout << "identifier " << node->get_name();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_bool_literal(bool_literal* node) {
dump_indent();
std::cout << "bool " << node->get_flag();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_vector_expr(vector_expr* node) {
dump_indent();
std::cout << "vector";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_elements()) {
if (i==node->get_elements().back()) {
@ -76,7 +77,7 @@ bool ast_dumper::visit_vector_expr(vector_expr* node) {
bool ast_dumper::visit_hash_expr(hash_expr* node) {
dump_indent();
std::cout << "hash";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_members()) {
if (i==node->get_members().back()) {
@ -91,7 +92,7 @@ bool ast_dumper::visit_hash_expr(hash_expr* node) {
bool ast_dumper::visit_hash_pair(hash_pair* node) {
dump_indent();
std::cout << "pair " << node->get_name();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
if (node->get_value()) {
push_indent();
set_last();
@ -104,7 +105,7 @@ bool ast_dumper::visit_hash_pair(hash_pair* node) {
bool ast_dumper::visit_function(function* node) {
dump_indent();
std::cout << "function";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_parameter_list()) {
i->accept(this);
@ -118,7 +119,7 @@ bool ast_dumper::visit_function(function* node) {
bool ast_dumper::visit_code_block(code_block* node) {
dump_indent();
std::cout << "block";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_expressions()) {
if (i==node->get_expressions().back()) {
@ -133,7 +134,7 @@ bool ast_dumper::visit_code_block(code_block* node) {
bool ast_dumper::visit_parameter(parameter* node) {
dump_indent();
std::cout << "parameter " << node->get_parameter_name();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
if (node->get_default_value()) {
push_indent();
set_last();
@ -146,7 +147,7 @@ bool ast_dumper::visit_parameter(parameter* node) {
bool ast_dumper::visit_ternary_operator(ternary_operator* node) {
dump_indent();
std::cout << "ternary_operator";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_condition()->accept(this);
node->get_left()->accept(this);
@ -166,7 +167,7 @@ bool ast_dumper::visit_binary_operator(binary_operator* node) {
return true;
}
dump_indent();
std::cout << "binary_operator ";
std::cout << "binary_operator \"";
switch(node->get_operator_type()) {
case binary_operator::binary_type::add: std::cout << "+"; break;
case binary_operator::binary_type::sub: std::cout << "-"; break;
@ -185,7 +186,7 @@ bool ast_dumper::visit_binary_operator(binary_operator* node) {
case binary_operator::binary_type::condition_and: std::cout << "and"; break;
case binary_operator::binary_type::condition_or: std::cout << "or"; break;
}
std::cout << format_location(node->get_location());
std::cout << "\"" << format_location(node);
push_indent();
node->get_left()->accept(this);
set_last();
@ -200,13 +201,13 @@ bool ast_dumper::visit_unary_operator(unary_operator* node) {
return true;
}
dump_indent();
std::cout << "unary_operator ";
std::cout << "unary_operator \"";
switch(node->get_operator_type()) {
case unary_operator::unary_type::negative: std::cout << "-"; break;
case unary_operator::unary_type::logical_not: std::cout << "!"; break;
case unary_operator::unary_type::bitwise_not: std::cout << "~"; break;
}
std::cout << format_location(node->get_location());
std::cout << "\"" << format_location(node);
push_indent();
set_last();
node->get_value()->accept(this);
@ -217,7 +218,7 @@ bool ast_dumper::visit_unary_operator(unary_operator* node) {
bool ast_dumper::visit_call_expr(call_expr* node) {
dump_indent();
std::cout << "call_expr";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
if (!node->get_calls().size()) {
set_last();
@ -236,14 +237,14 @@ bool ast_dumper::visit_call_expr(call_expr* node) {
bool ast_dumper::visit_call_hash(call_hash* node) {
dump_indent();
std::cout << "call_hash " << node->get_field();
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_call_vector(call_vector* node) {
dump_indent();
std::cout << "call_vector";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_slices()) {
if (i==node->get_slices().back()) {
@ -258,7 +259,7 @@ bool ast_dumper::visit_call_vector(call_vector* node) {
bool ast_dumper::visit_call_function(call_function* node) {
dump_indent();
std::cout << "call_function";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_argument()) {
if (i==node->get_argument().back()) {
@ -273,7 +274,7 @@ bool ast_dumper::visit_call_function(call_function* node) {
bool ast_dumper::visit_slice_vector(slice_vector* node) {
dump_indent();
std::cout << "slice";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
if (!node->get_end()) {
set_last();
@ -290,7 +291,7 @@ bool ast_dumper::visit_slice_vector(slice_vector* node) {
bool ast_dumper::visit_definition_expr(definition_expr* node) {
dump_indent();
std::cout << "definition";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
if (node->get_variable_name()) {
node->get_variable_name()->accept(this);
@ -321,7 +322,7 @@ bool ast_dumper::visit_assignment_expr(assignment_expr* node) {
case assignment_expr::assign_type::bitwise_or_equal: std::cout << "|="; break;
case assignment_expr::assign_type::bitwise_xor_equal: std::cout << "^="; break;
}
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_left()->accept(this);
set_last();
@ -333,7 +334,7 @@ bool ast_dumper::visit_assignment_expr(assignment_expr* node) {
bool ast_dumper::visit_multi_identifier(multi_identifier* node) {
dump_indent();
std::cout << "multiple_identifier";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_variables()) {
if (i==node->get_variables().back()) {
@ -348,7 +349,7 @@ bool ast_dumper::visit_multi_identifier(multi_identifier* node) {
bool ast_dumper::visit_tuple_expr(tuple_expr* node) {
dump_indent();
std::cout << "tuple";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
for(auto i : node->get_elements()) {
if (i==node->get_elements().back()) {
@ -363,7 +364,7 @@ bool ast_dumper::visit_tuple_expr(tuple_expr* node) {
bool ast_dumper::visit_multi_assign(multi_assign* node) {
dump_indent();
std::cout << "multiple_assignment";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_tuple()->accept(this);
set_last();
@ -375,7 +376,7 @@ bool ast_dumper::visit_multi_assign(multi_assign* node) {
bool ast_dumper::visit_while_expr(while_expr* node) {
dump_indent();
std::cout << "while";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_condition()->accept(this);
set_last();
@ -387,7 +388,7 @@ bool ast_dumper::visit_while_expr(while_expr* node) {
bool ast_dumper::visit_for_expr(for_expr* node) {
dump_indent();
std::cout << "for";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_initial()->accept(this);
node->get_condition()->accept(this);
@ -405,7 +406,7 @@ bool ast_dumper::visit_iter_expr(iter_expr* node) {
} else {
std::cout << "iterator";
}
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
set_last();
if (node->get_name()) {
@ -424,7 +425,7 @@ bool ast_dumper::visit_forei_expr(forei_expr* node) {
} else {
std::cout << "forindex";
}
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
node->get_iterator()->accept(this);
node->get_value()->accept(this);
@ -437,7 +438,7 @@ bool ast_dumper::visit_forei_expr(forei_expr* node) {
bool ast_dumper::visit_condition_expr(condition_expr* node) {
dump_indent();
std::cout << "condition";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
if (!node->get_elsif_stataments().size() &&
!node->get_else_statement()) {
@ -462,7 +463,7 @@ bool ast_dumper::visit_condition_expr(condition_expr* node) {
bool ast_dumper::visit_if_expr(if_expr* node) {
dump_indent();
std::cout << "if";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
push_indent();
if (node->get_condition()) {
node->get_condition()->accept(this);
@ -476,21 +477,21 @@ bool ast_dumper::visit_if_expr(if_expr* node) {
bool ast_dumper::visit_continue_expr(continue_expr* node) {
dump_indent();
std::cout << "continue";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_break_expr(break_expr* node) {
dump_indent();
std::cout << "break";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
return true;
}
bool ast_dumper::visit_return_expr(return_expr* node) {
dump_indent();
std::cout << "return";
std::cout << format_location(node->get_location());
std::cout << format_location(node);
if (node->get_value()) {
push_indent();
set_last();

View File

@ -1,88 +1,100 @@
#pragma once
#include "ast_visitor.h"
#include <iostream>
#include <cstring>
#include <sstream>
#include <vector>
namespace nasal {
class ast_dumper: public ast_visitor {
private:
std::vector<std::string> indent;
private:
void push_indent() {
if (indent.size()) {
if (indent.back()=="|--") {
indent.back() = "| ";
} else if (indent.back()=="+--") {
indent.back() = " ";
}
}
indent.push_back("|--");
}
void pop_indent() {indent.pop_back();}
void set_last() {indent.back() = "+--";}
void dump_indent() {
if (indent.size() && indent.back()=="| ") {
indent.back() = "|--";
}
for(const auto& i : indent) {
std::cout << i;
}
}
std::string format_location(const span& location) {
std::stringstream ss;
ss << " -> ";
location.dump_begin(ss);
ss << "\n";
return ss.str();
}
public:
bool visit_use_stmt(use_stmt*) override;
bool visit_null_expr(null_expr*) override;
bool visit_nil_expr(nil_expr*) override;
bool visit_number_literal(number_literal*) override;
bool visit_string_literal(string_literal*) override;
bool visit_identifier(identifier*) override;
bool visit_bool_literal(bool_literal*) override;
bool visit_vector_expr(vector_expr*) override;
bool visit_hash_expr(hash_expr*) override;
bool visit_hash_pair(hash_pair*) override;
bool visit_function(function*) override;
bool visit_code_block(code_block*) override;
bool visit_parameter(parameter*) override;
bool visit_ternary_operator(ternary_operator*) override;
bool visit_binary_operator(binary_operator*) override;
bool visit_unary_operator(unary_operator*) override;
bool visit_call_expr(call_expr*) override;
bool visit_call_hash(call_hash*) override;
bool visit_call_vector(call_vector*) override;
bool visit_call_function(call_function*) override;
bool visit_slice_vector(slice_vector*) override;
bool visit_definition_expr(definition_expr*) override;
bool visit_assignment_expr(assignment_expr*) override;
bool visit_multi_identifier(multi_identifier*) override;
bool visit_tuple_expr(tuple_expr*) override;
bool visit_multi_assign(multi_assign*) override;
bool visit_while_expr(while_expr*) override;
bool visit_for_expr(for_expr*) override;
bool visit_iter_expr(iter_expr*) override;
bool visit_forei_expr(forei_expr*) override;
bool visit_condition_expr(condition_expr*) override;
bool visit_if_expr(if_expr*) override;
bool visit_continue_expr(continue_expr*) override;
bool visit_break_expr(break_expr*) override;
bool visit_return_expr(return_expr*) override;
public:
void dump(code_block* root) {
root->accept(this);
}
};
}
#pragma once
#include "ast_visitor.h"
#include "util/util.h"
#include <iostream>
#include <cstring>
#include <sstream>
#include <vector>
namespace nasal {
class ast_dumper: public ast_visitor {
private:
std::vector<std::string> indent;
private:
void push_indent() {
if (indent.size()) {
if (indent.back()=="├──") {
indent.back() = "";
} else if (indent.back()=="╰──") {
indent.back() = " ";
}
}
indent.push_back("├──");
}
void pop_indent() {
indent.pop_back();
}
void set_last() {
indent.back() = "╰──";
}
void dump_indent() {
if (indent.size() && indent.back()=="") {
indent.back() = "├──";
}
for(const auto& i : indent) {
std::cout << i;
}
}
std::string format_location(expr* node) {
std::stringstream ss;
ss << " → [";
node->get_location().dump_begin(ss);
ss << "]\n";
return ss.str();
}
public:
bool visit_use_stmt(use_stmt*) override;
bool visit_null_expr(null_expr*) override;
bool visit_nil_expr(nil_expr*) override;
bool visit_number_literal(number_literal*) override;
bool visit_string_literal(string_literal*) override;
bool visit_identifier(identifier*) override;
bool visit_bool_literal(bool_literal*) override;
bool visit_vector_expr(vector_expr*) override;
bool visit_hash_expr(hash_expr*) override;
bool visit_hash_pair(hash_pair*) override;
bool visit_function(function*) override;
bool visit_code_block(code_block*) override;
bool visit_parameter(parameter*) override;
bool visit_ternary_operator(ternary_operator*) override;
bool visit_binary_operator(binary_operator*) override;
bool visit_unary_operator(unary_operator*) override;
bool visit_call_expr(call_expr*) override;
bool visit_call_hash(call_hash*) override;
bool visit_call_vector(call_vector*) override;
bool visit_call_function(call_function*) override;
bool visit_slice_vector(slice_vector*) override;
bool visit_definition_expr(definition_expr*) override;
bool visit_assignment_expr(assignment_expr*) override;
bool visit_multi_identifier(multi_identifier*) override;
bool visit_tuple_expr(tuple_expr*) override;
bool visit_multi_assign(multi_assign*) override;
bool visit_while_expr(while_expr*) override;
bool visit_for_expr(for_expr*) override;
bool visit_iter_expr(iter_expr*) override;
bool visit_forei_expr(forei_expr*) override;
bool visit_condition_expr(condition_expr*) override;
bool visit_if_expr(if_expr*) override;
bool visit_continue_expr(continue_expr*) override;
bool visit_break_expr(break_expr*) override;
bool visit_return_expr(return_expr*) override;
public:
void dump(code_block* root) {
util::windows_code_page_manager wcpm;
wcpm.set_utf8_output();
root->accept(this);
wcpm.restore_code_page();
}
};
}

26
src/cli/cli.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "cli/cli.h"
#include <iostream>
namespace nasal::cli {
cli_config parse(const std::vector<std::string>& args) {
cli_config result;
for(const auto& arg : args) {
if (cli_options.count(arg)) {
result.options.insert(cli_options.at(arg));
} else if (!result.input_file_path.length()) {
result.input_file_path = arg;
} else {
result.nasal_vm_args.push_back(arg);
}
}
if (result.input_file_path.length() && result.options.empty()) {
result.options.insert(option::cli_execute);
}
return result;
}
}

70
src/cli/cli.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include <cstring>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace nasal::cli {
enum class option {
cli_help,
cli_version,
cli_repl_mode,
cli_view_ast,
cli_view_raw_ast,
cli_view_code,
cli_show_symbol,
cli_execute,
cli_show_execute_time,
cli_detail_info,
cli_show_referenced_file,
cli_debug_mode,
cli_profile,
cli_profile_all,
cli_limit_mode
};
struct cli_config {
std::string input_file_path = "";
std::unordered_set<option> options = {};
std::vector<std::string> nasal_vm_args = {};
bool has(option opt) const {
return options.count(opt);
}
};
const std::unordered_map<std::string, option> cli_options = {
{"-h", option::cli_help},
{"--help", option::cli_help},
{"-v", option::cli_version},
{"--version", option::cli_version},
{"-r", option::cli_repl_mode},
{"--repl", option::cli_repl_mode},
{"-a", option::cli_view_ast},
{"--ast", option::cli_view_ast},
{"--raw-ast", option::cli_view_raw_ast},
{"-c", option::cli_view_code},
{"--code", option::cli_view_code},
{"-s", option::cli_show_symbol},
{"--symbol", option::cli_show_symbol},
{"-e", option::cli_execute},
{"--exec", option::cli_execute},
{"-t", option::cli_show_execute_time},
{"--time", option::cli_show_execute_time},
{"-d", option::cli_detail_info},
{"--detail", option::cli_detail_info},
{"-f", option::cli_show_referenced_file},
{"--ref-file", option::cli_show_referenced_file},
{"-dbg", option::cli_debug_mode},
{"--debug", option::cli_debug_mode},
{"--prof", option::cli_profile},
{"--prof-all", option::cli_profile_all},
{"--limit", option::cli_limit_mode}
};
cli_config parse(const std::vector<std::string>&);
}

View File

@ -13,39 +13,26 @@
#include "nasal_codegen.h"
#include "nasal_vm.h"
#include "nasal_dbg.h"
#include "repl.h"
#include "util/util.h"
#include "repl/repl.h"
#include "cli/cli.h"
#include <unordered_map>
#include <thread>
#include <cstdlib>
const u32 VM_RAW_AST = 1;
const u32 VM_AST = 1<<1;
const u32 VM_CODE = 1<<2;
const u32 VM_TIME = 1<<3;
const u32 VM_EXEC = 1<<4;
const u32 VM_DETAIL = 1<<5;
const u32 VM_DEBUG = 1<<6;
const u32 VM_SYMINFO = 1<<7;
const u32 VM_PROFILE = 1<<8;
const u32 VM_PROF_ALL = 1<<9;
const u32 VM_REF_FILE = 1<<10;
const u32 VM_LIMIT = 1<<11;
std::ostream& help(std::ostream& out) {
out
<< "\n"
<< " ,--#-,\n"
<< "<3 / \\____\\ <3\n"
<< " |_|__A_|\n"
#ifdef _WIN32
<< "use command <chcp 65001> to use unicode.\n"
#endif
<< "\nnasal <option>\n"
<< "option:\n"
<< " -h, --help | get help.\n"
<< " -v, --version | get version.\n"
<< " -r, --repl | use repl interpreter(experimental).\n"
<< " -r, --repl | use repl interpreter.\n"
<< "\nnasal [option] <file> [argv]\n"
<< "option:\n"
<< " -a, --ast | view ast after link/optimize process.\n"
@ -80,7 +67,7 @@ std::ostream& logo(std::ostream& out) {
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<< "\n"
<< "ver : " << __nasver__
<< " " << nasal::get_platform() << " " << nasal::get_arch()
<< " " << nasal::util::get_platform() << " " << nasal::util::get_arch()
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
<< "std : c++ " << __cplusplus << "\n"
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
@ -88,7 +75,9 @@ std::ostream& logo(std::ostream& out) {
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
<< "\n"
<< "presented by fgprc members - http://fgprc.org.cn\n"
<< "presented by fgprc members\n"
<< " - http://fgprc.org\n"
<< " - http://fgprc.org.cn\n"
<< "\n"
<< "input <nasal -h> to get help .\n\n";
return out;
@ -101,28 +90,25 @@ std::ostream& version(std::ostream& out) {
for(u32 i = 0; i<5; ++i) {
num = (num+rand())*(1.0/(RAND_MAX+1.0));
}
if (num<0.01) {
// give you 5% to see this easter egg
if (num<0.05) {
nasal::parse::easter_egg();
}
out << "nasal interpreter version " << __nasver__;
out << " " << nasal::get_platform() << " " << nasal::get_arch();
out << "nasal version " << __nasver__;
out << " " << nasal::util::get_platform() << " " << nasal::util::get_arch();
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
return out;
}
[[noreturn]]
void err() {
std::cerr
<< "invalid argument(s).\n"
<< "use <nasal -h> to get help.\n";
std::cerr << "invalid argument(s), use <nasal -h> to get help.\n";
std::exit(1);
}
void execute(const std::string& file,
const std::vector<std::string>& argv,
const u32 cmd) {
void execute(const nasal::cli::cli_config& config) {
using option = nasal::cli::option;
using clk = std::chrono::high_resolution_clock;
const auto den = clk::duration::period::den;
@ -132,17 +118,17 @@ void execute(const std::string& file,
nasal::codegen gen;
// lexer scans file to get tokens
lex.scan(file).chkerr();
lex.scan(config.input_file_path).chkerr();
// parser gets lexer's token list to compile
parse.compile(lex).chkerr();
if (cmd&VM_RAW_AST) {
if (config.has(option::cli_view_raw_ast)) {
nasal::ast_dumper().dump(parse.tree());
}
// linker gets parser's ast and load import files to this ast
ld.link(parse, cmd&VM_DETAIL).chkerr();
if (cmd&VM_REF_FILE) {
ld.link(parse, config.has(option::cli_detail_info)).chkerr();
if (config.has(option::cli_show_referenced_file)) {
if (ld.get_file_list().size()) {
std::cout << "referenced file(s):\n";
}
@ -154,34 +140,43 @@ void execute(const std::string& file,
// optimizer does simple optimization on ast
auto opt = std::make_unique<nasal::optimizer>();
opt->do_optimization(parse.tree());
if (cmd&VM_AST) {
if (config.has(option::cli_view_ast)) {
nasal::ast_dumper().dump(parse.tree());
}
// code generator gets parser's ast and import file list to generate code
gen.compile(parse, ld, false, cmd&VM_LIMIT).chkerr();
if (cmd&VM_CODE) {
gen.compile(parse, ld, false, config.has(option::cli_limit_mode)).chkerr();
if (config.has(option::cli_view_code)) {
gen.print(std::cout);
}
if (cmd&VM_SYMINFO) {
if (config.has(option::cli_show_symbol)) {
gen.symbol_dump(std::cout);
}
// run
const auto start = clk::now();
if (cmd&VM_DEBUG) {
if (config.has(option::cli_debug_mode)) {
auto debugger = std::make_unique<nasal::dbg>();
debugger->run(gen, ld, argv, cmd&VM_PROFILE, cmd&VM_PROF_ALL);
} else if (cmd&VM_TIME || cmd&VM_EXEC) {
debugger->run(
gen,
ld,
config.nasal_vm_args,
config.has(option::cli_profile),
config.has(option::cli_profile_all)
);
} else if (config.has(option::cli_show_execute_time) ||
config.has(option::cli_detail_info) ||
config.has(option::cli_limit_mode) ||
config.has(option::cli_execute)) {
auto runtime = std::make_unique<nasal::vm>();
runtime->set_detail_report_info(cmd&VM_DETAIL);
runtime->set_limit_mode_flag(cmd&VM_LIMIT);
runtime->run(gen, ld, argv);
runtime->set_detail_report_info(config.has(option::cli_detail_info));
runtime->set_limit_mode_flag(config.has(option::cli_limit_mode));
runtime->run(gen, ld, config.nasal_vm_args);
}
// get running time
const auto end = clk::now();
if (cmd&VM_TIME) {
if (config.has(option::cli_show_execute_time)) {
std::clog << "process exited after ";
std::clog << static_cast<f64>((end-start).count())/den << "s.\n\n";
}
@ -194,18 +189,20 @@ i32 main(i32 argc, const char* argv[]) {
return 0;
}
// the first argument is the executable itself, ignore it
const auto config = nasal::cli::parse({argv+1, argv+argc});
// run directly or show help
if (argc==2) {
std::string s(argv[1]);
if (s=="-h" || s=="--help") {
if (config.has(nasal::cli::option::cli_help)) {
std::clog << help;
} else if (s=="-v" || s=="--version") {
} else if (config.has(nasal::cli::option::cli_version)) {
std::clog << version;
} else if (s=="-r" || s=="--repl") {
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
auto repl = std::make_unique<nasal::repl::repl>();
repl->execute();
} else if (s[0]!='-') {
execute(s, {}, VM_EXEC);
} else if (config.input_file_path.size()) {
execute(config);
} else {
err();
}
@ -213,45 +210,6 @@ i32 main(i32 argc, const char* argv[]) {
}
// execute with arguments
const std::unordered_map<std::string, u32> command_list = {
{"--raw-ast", VM_RAW_AST},
{"--ast", VM_AST},
{"-a", VM_AST},
{"--code", VM_CODE},
{"-c", VM_CODE},
{"--symbol", VM_SYMINFO},
{"-s", VM_SYMINFO},
{"--exec", VM_EXEC},
{"-e", VM_EXEC},
{"--time", VM_TIME|VM_EXEC},
{"-t", VM_TIME|VM_EXEC},
{"--detail", VM_DETAIL|VM_EXEC},
{"-d", VM_DETAIL|VM_EXEC},
{"--debug", VM_DEBUG},
{"-dbg", VM_DEBUG},
{"--prof", VM_PROFILE},
{"--prof-all", VM_PROF_ALL},
{"-f", VM_REF_FILE},
{"--ref-file", VM_REF_FILE},
{"--limit", VM_LIMIT|VM_EXEC}
};
u32 commands = 0;
std::string filename = "";
std::vector<std::string> vm_argv;
for(i32 i = 1; i<argc; ++i) {
if (command_list.count(argv[i])) {
commands |= command_list.at(argv[i]);
} else if (!filename.length()) {
filename = argv[i];
} else {
vm_argv.push_back(argv[i]);
}
}
if (!filename.length()) {
err();
}
execute(filename, vm_argv, commands? commands:VM_EXEC);
execute(config);
return 0;
}

View File

@ -4,12 +4,8 @@
#define __nasver__ "11.2"
#endif
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <cstring>
#include <sstream>
#include <cmath>
// abbreviation of some useful basic type
using i32 = std::int32_t;
@ -21,61 +17,5 @@ using u64 = std::uint64_t;
using usize = std::size_t;
using f64 = double;
namespace nasal {
bool is_windows();
bool is_linux();
bool is_macos();
bool is_x86();
bool is_amd64();
bool is_x86_64();
bool is_arm();
bool is_aarch64();
bool is_ia64();
bool is_powerpc();
bool is_superh();
const char* get_platform();
const char* get_arch();
// virtual machine stack depth, both global depth and value stack depth
const u32 VM_STACK_DEPTH = UINT16_MAX;
f64 hex_to_f64(const char*);
f64 oct_to_f64(const char*);
// we have the same reason not using atof here
// just as andy's interpreter does.
// it is not platform independent, and may have strange output.
// so we write a new function here to convert str to number manually.
// but this also makes 0.1+0.2==0.3,
// not another result that you may get in other languages.
f64 dec_to_f64(const char*);
f64 str_to_num(const char*);
i32 utf8_hdchk(const char);
std::string char_to_hex(const char);
std::string rawstr(const std::string&, const usize maxlen = 0);
namespace fs {
class path {
private:
std::string file_system_path;
public:
path(const path&) = default;
path(const std::string& file_path): file_system_path(file_path) {}
path& operator/(const path&);
const char* c_str() const {
return file_system_path.c_str();
}
const std::string& str() const {
return file_system_path;
}
};
bool exists(const path&);
bool is_regular(const path&);
}
}

View File

@ -1,4 +1,5 @@
#include "nasal_codegen.h"
#include "util/util.h"
namespace nasal {
@ -239,9 +240,9 @@ void codegen::func_gen(function* node) {
}
}
usize newf=code.size();
const auto newf = code.size();
emit(op_newf, 0, node->get_location());
usize lsize=code.size();
const auto lsize = code.size();
emit(op_intl, 0, node->get_location());
// add special keyword 'me' into symbol table
@ -1390,7 +1391,7 @@ void codegen::print(std::ostream& out) {
// print const strings
for(const auto& str : const_string_table) {
out << " .symbol \"" << rawstr(str) << "\"\n";
out << " .symbol \"" << util::rawstr(str) << "\"\n";
}
// print blank line

View File

@ -8,7 +8,7 @@
#include "nasal_parse.h"
#include "nasal_import.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#include "natives/coroutine.h"
#include "natives/bits_lib.h"
#include "natives/math_lib.h"

View File

@ -13,7 +13,7 @@ void operand_line_counter::load_file_line_counter(
file_name_list = file_list;
file_line_counter = {};
file_contents = {};
flstream fs;
filestream fs;
for(usize i =0; i<file_list.size(); ++i) {
fs.load(file_list[i]);
file_contents.push_back(fs.file_content());

View File

@ -1,5 +1,5 @@
#include "nasal_err.h"
#include "repl.h"
#include "repl/repl.h"
namespace nasal {
@ -71,7 +71,7 @@ std::ostream& reset(std::ostream& s) {
return s;
}
void flstream::load(const std::string& f) {
void filestream::load(const std::string& f) {
if (file==f) { // don't need to load a loaded file
return;
}

View File

@ -29,13 +29,13 @@ std::ostream& orange(std::ostream&);
std::ostream& white(std::ostream&);
std::ostream& reset(std::ostream&);
class flstream {
class filestream {
protected:
std::string file;
std::vector<std::string> res;
public:
flstream(): file("") {}
filestream(): file("") {}
void load(const std::string&);
const std::string& operator[](usize n) const {return res[n];}
const auto& name() const {return file;}
@ -43,7 +43,7 @@ public:
usize size() const {return res.size();}
};
class error: public flstream {
class error: public filestream {
private:
u32 cnt; // counter for errors

View File

@ -301,17 +301,17 @@ void gc::info() const {
for(usize i = 0; i<indent; ++i) {
indent_string += "-";
}
auto last_line = indent_string + "+" +
indent_string + "-" + indent_string + "-" + indent_string;
const auto last_line = "+" + indent_string + "+" +
indent_string + "-" + indent_string + "-" + indent_string + "+";
indent_string = indent_string + "+" +
indent_string + "+" + indent_string + "+" + indent_string;
std::clog << "\n" << indent_string << "\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "object type";
std::clog << "\n+" << indent_string << "+\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "object type";
std::clog << " | " << left << setw(indent) << setfill(' ') << "gc count";
std::clog << " | " << left << setw(indent) << setfill(' ') << "alloc count";
std::clog << " | " << left << setw(indent) << setfill(' ') << "memory size";
std::clog << "\n" << indent_string << "\n";
std::clog << " |\n+" << indent_string << "+\n";
double total = 0;
for(u8 i = 0; i<gc_type_size; ++i) {
@ -319,33 +319,45 @@ void gc::info() const {
continue;
}
total += static_cast<f64>(gcnt[i]);
std::clog << " " << left << setw(indent) << setfill(' ') << name[i];
std::clog << "| " << left << setw(indent) << setfill(' ') << name[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << gcnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << acnt[i];
std::clog << " | " << left << setw(indent) << setfill(' ') << size[i];
std::clog << "\n";
std::clog << " |\n";
}
std::clog << indent_string << "\n";
std::clog << "+" << indent_string << "+\n";
auto den = std::chrono::high_resolution_clock::duration::period::den;
std::clog << " " << left << setw(indent) << setfill(' ') << "detail";
std::clog << "| " << left << setw(indent) << setfill(' ') << "detail";
std::clog << " | " << left << setw(indent) << setfill(' ') << "time spend";
std::clog << " | " << left << setw(indent) << setfill('x') << "x";
std::clog << " | " << left << setw(indent) << setfill('x') << "x";
std::clog << "\n" << indent_string << "\n";
std::clog << " |\n+" << indent_string << "+\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "gc time";
std::clog << " | " << setw(indent-3) << std::setprecision(4) << worktime*1.0/den*1000 << " ms";
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "avg time";
std::clog << " | " << setw(indent-3) << std::setprecision(4) << worktime*1.0/den*1000/total << " ms";
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max gc";
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_time*1.0/den*1000 << " ms";
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max mark";
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_mark_time*1.0/den*1000 << " ms";
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "max sweep";
std::clog << " | " << setw(indent-3) << std::setprecision(4) << max_sweep_time*1.0/den*1000 << " ms";
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << "| " << left << setw(indent) << setfill(' ') << "concurrent";
std::clog << " | " << setw(indent) << (flag_concurrent_mark_triggered? "true":"false");
std::clog << setw(indent*2+7) << " " << "|\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "gc time";
std::clog << " | " << worktime*1.0/den*1000 << " ms\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "avg time";
std::clog << " | " << worktime*1.0/den*1000/total << " ms\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "max gc";
std::clog << " | " << max_time*1.0/den*1000 << " ms\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "max mark";
std::clog << " | " << max_mark_time*1.0/den*1000 << " ms\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "max sweep";
std::clog << " | " << max_sweep_time*1.0/den*1000 << " ms\n";
std::clog << " " << left << setw(indent) << setfill(' ') << "concurrent";
std::clog << " | " << (flag_concurrent_mark_triggered? "true\n":"false\n");
std::clog << last_line << "\n";
}
@ -380,7 +392,7 @@ void gc::context_change(nas_co* co) {
}
void gc::context_reserve() {
// pc=0 means this coroutine is finished
// pc = 0 means this coroutine is finished
cort->status = running_context->pc?
nas_co::status::suspended:
nas_co::status::dead;

View File

@ -13,6 +13,7 @@
#include <thread>
#include <cstring>
#include <sstream>
#include <iostream>
#include "nasal.h"
#include "nasal_type.h"

View File

@ -1,5 +1,7 @@
#include "nasal_import.h"
#include "symbol_finder.h"
#include "util/util.h"
#include "util/fs.h"
#include <memory>
#include <unordered_set>
@ -7,7 +9,7 @@
namespace nasal {
linker::linker(): show_path_flag(false), this_file("") {
const auto seperator = is_windows()? ';':':';
const auto seperator = util::is_windows()? ';':':';
const auto PATH = std::string(getenv("PATH"));
usize last = 0, position = PATH.find(seperator, 0);
while(position!=std::string::npos) {
@ -30,7 +32,7 @@ std::string linker::get_path(expr* node) {
for(auto i : path) {
file_relative_path += i->get_name();
if (i!=path.back()) {
file_relative_path += (is_windows()? "\\":"/");
file_relative_path += (util::is_windows()? "\\":"/");
}
}
return file_relative_path + ".nas";
@ -60,7 +62,7 @@ std::string linker::find_real_file_path(const std::string& filename,
// we will find lib.nas in nasal std directory
if (filename=="lib.nas") {
return is_windows()?
return util::is_windows()?
find_real_file_path("std\\lib.nas", location):
find_real_file_path("std/lib.nas", location);
}

View File

@ -13,6 +13,7 @@
#include "nasal_lexer.h"
#include "nasal_parse.h"
#include "symbol_finder.h"
#include "util/fs.h"
#include <cstring>
#include <sstream>

View File

@ -5,7 +5,9 @@
#endif
#include "nasal_lexer.h"
#include "repl.h"
#include "repl/repl.h"
#include "util/util.h"
#include "util/fs.h"
namespace nasal {
@ -61,7 +63,7 @@ void lexer::err_char() {
char c = res[ptr++];
err.err("lexer",
{line, column-1, line, column, filename},
"invalid character 0x" + char_to_hex(c)
"invalid character 0x" + util::char_to_hex(c)
);
++invalid_char;
}
@ -75,6 +77,11 @@ void lexer::open(const std::string& file) {
return;
}
if (file.empty()) {
err.err("lexer", "empty input file");
err.chkerr();
}
// check file exsits and it is a regular file
if (!fs::is_regular(file)) {
err.err("lexer", "<"+file+"> is not a regular file");
@ -96,14 +103,14 @@ void lexer::open(const std::string& file) {
}
tok lexer::get_type(const std::string& str) {
return token_mapper.count(str)? token_mapper.at(str):tok::null;
return token_mapper.count(str)? token_mapper.at(str):tok::tk_null;
}
std::string lexer::utf8_gen() {
std::string str = "";
while(ptr<res.size() && res[ptr]<0) {
std::string tmp = "";
u32 nbytes = utf8_hdchk(res[ptr]);
u32 nbytes = util::utf8_hdchk(res[ptr]);
if (!nbytes) {
++ptr;
++column;
@ -120,9 +127,9 @@ std::string lexer::utf8_gen() {
// utf8 character's total length is 1+nbytes
if (tmp.length()!=1+nbytes) {
++column;
std::string utf_info = "0x" + char_to_hex(tmp[0]);
std::string utf_info = "0x" + util::char_to_hex(tmp[0]);
for(u32 i = 1; i<tmp.size(); ++i) {
utf_info += " 0x" + char_to_hex(tmp[i]);
utf_info += " 0x" + util::char_to_hex(tmp[i]);
}
err.err("lexer",
{line, column-1, line, column, filename},
@ -152,7 +159,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::tk_null)? type:tok::tk_id,
str
};
}
@ -174,7 +182,11 @@ token lexer::num_gen() {
"invalid number `"+str+"`"
);
}
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_num,
str
};
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
std::string str = "0o";
ptr += 2;
@ -193,7 +205,11 @@ token lexer::num_gen() {
"invalid number `"+str+"`"
);
}
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_num,
str
};
}
// generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
@ -213,7 +229,11 @@ token lexer::num_gen() {
{begin_line, begin_column, line, column, filename},
"invalid number `"+str+"`"
);
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_num,
"0"
};
}
}
if (ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) {
@ -231,11 +251,19 @@ token lexer::num_gen() {
{begin_line, begin_column, line, column, filename},
"invalid number `"+str+"`"
);
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_num,
"0"
};
}
}
column += str.length();
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_num,
str
};
}
token lexer::str_gen() {
@ -283,18 +311,26 @@ token lexer::str_gen() {
{begin_line, begin_column, line, column, filename},
"get EOF when generating string"
);
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_str,
str
};
}
++column;
// if is not utf8, 1+utf8_hdchk should be 1
if (begin=='`' && str.length()!=1+utf8_hdchk(str[0])) {
if (begin=='`' && str.length()!=1+util::utf8_hdchk(str[0])) {
err.err("lexer",
{begin_line, begin_column, line, column, filename},
"\'`\' is used for string including one character"
);
}
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
return {
{begin_line, begin_column, line, column, filename},
tok::tk_str,
str
};
}
token lexer::single_opr() {
@ -303,7 +339,7 @@ token lexer::single_opr() {
std::string str(1, res[ptr]);
++column;
tok type = get_type(str);
if (type==tok::null) {
if (type==tok::tk_null) {
err.err("lexer",
{begin_line, begin_column, line, column, filename},
"invalid operator `"+str+"`"
@ -380,10 +416,14 @@ 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>"});
toks.push_back({toks.back().loc, tok::tk_eof, "<eof>"});
} else {
// if token sequence is empty, generate a default location
toks.push_back({{line, column, line, column, filename}, tok::eof, "<eof>"});
toks.push_back({
{line, column, line, column, filename},
tok::tk_eof,
"<eof>"
});
}
res = "";
return err;

View File

@ -16,66 +16,66 @@
namespace nasal {
enum class tok:u32 {
null=0, // null token (default token type)
num, // number literal
str, // string literal
id, // identifier
tktrue, // keyword true
tkfalse, // keyword false
use, // keyword use
rfor, // loop keyword for
forindex, // loop keyword forindex
foreach, // loop keyword foreach
rwhile, // loop keyword while
var, // keyword for definition
func, // keyword for definition of function
brk, // loop keyword break
cont, // loop keyword continue
ret, // function keyword return
rif, // condition expression keyword if
elsif, // condition expression keyword elsif
relse, // condition expression keyword else
nil, // nil literal
lcurve, // (
rcurve, // )
lbracket, // [
rbracket, // ]
lbrace, // {
rbrace, // }
semi, // ;
opand, // operator and
opor, // operator or
comma, // ,
dot, // .
ellipsis, // ...
quesmark, // ?
colon, // :
add, // operator +
sub, // operator -
mult, // operator *
div, // operator /
floater, // operator ~ and binary operator ~
btand, // bitwise operator &
btor, // bitwise operator |
btxor, // bitwise operator ^
opnot, // operator !
eq, // operator =
addeq, // operator +=
subeq, // operator -=
multeq, // operator *=
diveq, // operator /=
lnkeq, // operator ~=
btandeq, // operator &=
btoreq, // operator |=
btxoreq, // operator ^=
cmpeq, // operator ==
neq, // operator !=
less, // operator <
leq, // operator <=
grt, // operator >
geq, // operator >=
eof // <eof> end of token list
enum class tok {
tk_null = 0, // null token (default token type)
tk_num, // number literal
tk_str, // string literal
tk_id, // identifier
tk_true, // keyword true
tk_false, // keyword false
tk_use, // keyword use
tk_for, // loop keyword for
tk_forindex, // loop keyword forindex
tk_foreach, // loop keyword foreach
tk_while, // loop keyword while
tk_var, // keyword for definition
tk_func, // keyword for definition of function
tk_brk, // loop keyword break
tk_cont, // loop keyword continue
tk_ret, // function keyword return
tk_if, // condition expression keyword if
tk_elsif, // condition expression keyword elsif
tk_else, // condition expression keyword else
tk_nil, // nil literal
tk_lcurve, // (
tk_rcurve, // )
tk_lbracket, // [
tk_rbracket, // ]
tk_lbrace, // {
tk_rbrace, // }
tk_semi, // ;
tk_and, // operator and
tk_or, // operator or
tk_comma, // ,
tk_dot, // .
tk_ellipsis, // ...
tk_quesmark, // ?
tk_colon, // :
tk_add, // operator +
tk_sub, // operator -
tk_mult, // operator *
tk_div, // operator /
tk_floater, // operator ~ and binary operator ~
tk_btand, // bitwise operator &
tk_btor, // bitwise operator |
tk_btxor, // bitwise operator ^
tk_not, // operator !
tk_eq, // operator =
tk_addeq, // operator +=
tk_subeq, // operator -=
tk_multeq, // operator *=
tk_diveq, // operator /=
tk_lnkeq, // operator ~=
tk_btandeq, // operator &=
tk_btoreq, // operator |=
tk_btxoreq, // operator ^=
tk_cmpeq, // operator ==
tk_neq, // operator !=
tk_less, // operator <
tk_leq, // operator <=
tk_grt, // operator >
tk_geq, // operator >=
tk_eof // <eof> end of token list
};
struct token {
@ -99,60 +99,60 @@ private:
std::vector<token> toks;
const std::unordered_map<std::string, tok> token_mapper = {
{"use" ,tok::use },
{"true" ,tok::tktrue },
{"false" ,tok::tkfalse },
{"for" ,tok::rfor },
{"forindex",tok::forindex},
{"foreach" ,tok::foreach },
{"while" ,tok::rwhile },
{"var" ,tok::var },
{"func" ,tok::func },
{"break" ,tok::brk },
{"continue",tok::cont },
{"return" ,tok::ret },
{"if" ,tok::rif },
{"elsif" ,tok::elsif },
{"else" ,tok::relse },
{"nil" ,tok::nil },
{"(" ,tok::lcurve },
{")" ,tok::rcurve },
{"[" ,tok::lbracket},
{"]" ,tok::rbracket},
{"{" ,tok::lbrace },
{"}" ,tok::rbrace },
{";" ,tok::semi },
{"and" ,tok::opand },
{"or" ,tok::opor },
{"," ,tok::comma },
{"." ,tok::dot },
{"..." ,tok::ellipsis},
{"?" ,tok::quesmark},
{":" ,tok::colon },
{"+" ,tok::add },
{"-" ,tok::sub },
{"*" ,tok::mult },
{"/" ,tok::div },
{"~" ,tok::floater },
{"&" ,tok::btand },
{"|" ,tok::btor },
{"^" ,tok::btxor },
{"!" ,tok::opnot },
{"=" ,tok::eq },
{"+=" ,tok::addeq },
{"-=" ,tok::subeq },
{"*=" ,tok::multeq },
{"/=" ,tok::diveq },
{"~=" ,tok::lnkeq },
{"&=" ,tok::btandeq },
{"|=" ,tok::btoreq },
{"^=" ,tok::btxoreq },
{"==" ,tok::cmpeq },
{"!=" ,tok::neq },
{"<" ,tok::less },
{"<=" ,tok::leq },
{">" ,tok::grt },
{">=" ,tok::geq }
{"use" , tok::tk_use },
{"true" , tok::tk_true },
{"false" , tok::tk_false },
{"for" , tok::tk_for },
{"forindex", tok::tk_forindex},
{"foreach" , tok::tk_foreach },
{"while" , tok::tk_while },
{"var" , tok::tk_var },
{"func" , tok::tk_func },
{"break" , tok::tk_brk },
{"continue", tok::tk_cont },
{"return" , tok::tk_ret },
{"if" , tok::tk_if },
{"elsif" , tok::tk_elsif },
{"else" , tok::tk_else },
{"nil" , tok::tk_nil },
{"(" , tok::tk_lcurve },
{")" , tok::tk_rcurve },
{"[" , tok::tk_lbracket},
{"]" , tok::tk_rbracket},
{"{" , tok::tk_lbrace },
{"}" , tok::tk_rbrace },
{";" , tok::tk_semi },
{"and" , tok::tk_and },
{"or" , tok::tk_or },
{"," , tok::tk_comma },
{"." , tok::tk_dot },
{"..." , tok::tk_ellipsis},
{"?" , tok::tk_quesmark},
{":" , tok::tk_colon },
{"+" , tok::tk_add },
{"-" , tok::tk_sub },
{"*" , tok::tk_mult },
{"/" , tok::tk_div },
{"~" , tok::tk_floater },
{"&" , tok::tk_btand },
{"|" , tok::tk_btor },
{"^" , tok::tk_btxor },
{"!" , tok::tk_not },
{"=" , tok::tk_eq },
{"+=" , tok::tk_addeq },
{"-=" , tok::tk_subeq },
{"*=" , tok::tk_multeq },
{"/=" , tok::tk_diveq },
{"~=" , tok::tk_lnkeq },
{"&=" , tok::tk_btandeq },
{"|=" , tok::tk_btoreq },
{"^=" , tok::tk_btxoreq },
{"==" , tok::tk_cmpeq },
{"!=" , tok::tk_neq },
{"<" , tok::tk_less },
{"<=" , tok::tk_leq },
{">" , tok::tk_grt },
{">=" , tok::tk_geq }
};
tok get_type(const std::string&);

View File

@ -1,4 +1,5 @@
#include "nasal_opcode.h"
#include "util/util.h"
namespace nasal {
@ -48,7 +49,7 @@ void codestream::dump(std::ostream& out) const {
// dump operand index and bytecode(hex format)
out << hex << "0x"
<< setw(6) << setfill('0') << index << " "
<< setw(8) << setfill('0') << index << " "
<< setw(2) << setfill('0') << static_cast<u32>(op) << ":" << dec;
// dump immediate number(hex format)
@ -80,7 +81,7 @@ void codestream::dump(std::ostream& out) const {
break;
case op_lnkeqc:
out << hex << "0x" << num << dec;
out << " (" << rawstr(const_string[num], 16) << ")";
out << " (" << util::rawstr(const_string[num], 16) << ")";
break;
case op_addecp:
case op_subecp:
@ -91,7 +92,7 @@ void codestream::dump(std::ostream& out) const {
break;
case op_lnkecp:
out << hex << "0x" << num << dec;
out << " (" << rawstr(const_string[num], 16) << ") sp-1";
out << " (" << util::rawstr(const_string[num], 16) << ") sp-1";
break;
case op_addc:
case op_subc:
@ -141,7 +142,7 @@ void codestream::dump(std::ostream& out) const {
case op_deft:
case op_dyn:
out << hex << "0x" << num << dec;
out << " (" << rawstr(const_string[num], 16) << ")";
out << " (" << util::rawstr(const_string[num], 16) << ")";
break;
default:
if (files) {

View File

@ -1,7 +1,7 @@
#pragma once
#include "nasal.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#include <iostream>

File diff suppressed because it is too large Load Diff

View File

@ -16,66 +16,68 @@ class parse {
private:
u64 ptr;
u64 in_func; // count function block
u64 in_loop; // count loop block
u64 in_func_depth; // count function block
u64 in_loop_depth; // count loop block
const token* toks;
code_block* root;
error err;
private:
const std::unordered_map<tok, std::string> tokname {
{tok::use ,"use" },
{tok::rfor ,"for" },
{tok::forindex,"forindex"},
{tok::foreach ,"foreach" },
{tok::rwhile ,"while" },
{tok::var ,"var" },
{tok::func ,"func" },
{tok::brk ,"break" },
{tok::cont ,"continue"},
{tok::ret ,"return" },
{tok::rif ,"if" },
{tok::elsif ,"elsif" },
{tok::relse ,"else" },
{tok::nil ,"nil" },
{tok::lcurve ,"(" },
{tok::rcurve ,")" },
{tok::lbracket,"[" },
{tok::rbracket,"]" },
{tok::lbrace ,"{" },
{tok::rbrace ,"}" },
{tok::semi ,";" },
{tok::opand ,"and" },
{tok::opor ,"or" },
{tok::comma ,"," },
{tok::dot ,"." },
{tok::ellipsis,"..." },
{tok::quesmark,"?" },
{tok::colon ,":" },
{tok::add ,"+" },
{tok::sub ,"-" },
{tok::mult ,"*" },
{tok::div ,"/" },
{tok::floater ,"~" },
{tok::btand ,"&" },
{tok::btor ,"|" },
{tok::btxor ,"^" },
{tok::opnot ,"!" },
{tok::eq ,"=" },
{tok::addeq ,"+=" },
{tok::subeq ,"-=" },
{tok::multeq ,"*=" },
{tok::diveq ,"/=" },
{tok::lnkeq ,"~=" },
{tok::btandeq ,"&=" },
{tok::btoreq ,"|=" },
{tok::btxoreq ,"^=" },
{tok::cmpeq ,"==" },
{tok::neq ,"!=" },
{tok::less ,"<" },
{tok::leq ,"<=" },
{tok::grt ,">" },
{tok::geq ,">=" }
const std::unordered_map<tok, std::string> tokname = {
{tok::tk_true , "true" },
{tok::tk_false , "false" },
{tok::tk_use , "use" },
{tok::tk_for , "for" },
{tok::tk_forindex, "forindex"},
{tok::tk_foreach , "foreach" },
{tok::tk_while , "while" },
{tok::tk_var , "var" },
{tok::tk_func , "func" },
{tok::tk_brk , "break" },
{tok::tk_cont , "continue"},
{tok::tk_ret , "return" },
{tok::tk_if , "if" },
{tok::tk_elsif , "elsif" },
{tok::tk_else , "else" },
{tok::tk_nil , "nil" },
{tok::tk_lcurve , "(" },
{tok::tk_rcurve , ")" },
{tok::tk_lbracket, "[" },
{tok::tk_rbracket, "]" },
{tok::tk_lbrace , "{" },
{tok::tk_rbrace , "}" },
{tok::tk_semi , ";" },
{tok::tk_and , "and" },
{tok::tk_or , "or" },
{tok::tk_comma , "," },
{tok::tk_dot , "." },
{tok::tk_ellipsis, "..." },
{tok::tk_quesmark, "?" },
{tok::tk_colon , ":" },
{tok::tk_add , "+" },
{tok::tk_sub , "-" },
{tok::tk_mult , "*" },
{tok::tk_div , "/" },
{tok::tk_floater , "~" },
{tok::tk_btand , "&" },
{tok::tk_btor , "|" },
{tok::tk_btxor , "^" },
{tok::tk_not , "!" },
{tok::tk_eq , "=" },
{tok::tk_addeq , "+=" },
{tok::tk_subeq , "-=" },
{tok::tk_multeq , "*=" },
{tok::tk_diveq , "/=" },
{tok::tk_lnkeq , "~=" },
{tok::tk_btandeq , "&=" },
{tok::tk_btoreq , "|=" },
{tok::tk_btxoreq , "^=" },
{tok::tk_cmpeq , "==" },
{tok::tk_neq , "!=" },
{tok::tk_less , "<" },
{tok::tk_leq , "<=" },
{tok::tk_grt , ">" },
{tok::tk_geq , ">=" }
};
private:
@ -151,7 +153,8 @@ public:
}
public:
parse(): ptr(0), in_func(0), in_loop(0), toks(nullptr), root(nullptr) {}
parse(): ptr(0), in_func_depth(0), in_loop_depth(0),
toks(nullptr), root(nullptr) {}
~parse() {delete root;}
const error& compile(const lexer&);
static void easter_egg();

View File

@ -1,4 +1,5 @@
#include "nasal_type.h"
#include "util/util.h"
#include <cstring>
#include <sstream>
@ -268,7 +269,7 @@ void nas_val::clear() {
}
f64 var::to_num() {
return type!=vm_type::vm_str? val.num:str_to_num(str().c_str());
return type!=vm_type::vm_str? val.num:util::str_to_num(str().c_str());
}
std::string var::to_str() {
@ -384,7 +385,7 @@ nas_map& var::map() {
}
var nas_err(const std::string& error_function_name, const std::string& info) {
std::cerr << "\n[vm] " << error_function_name << ": " << info << "\n";
std::cerr << "[vm] " << error_function_name << ": " << info << "\n";
return var::none();
}

View File

@ -2,6 +2,9 @@
#include "nasal.h"
#include <cstring>
#include <sstream>
#include <iostream>
#include <vector>
#include <unordered_map>

View File

@ -1,4 +1,5 @@
#include "nasal_vm.h"
#include "util/util.h"
namespace nasal {
@ -75,8 +76,8 @@ void vm::value_info(var& val) {
case vm_type::vm_nil: std::clog << "| nil |"; break;
case vm_type::vm_num: std::clog << "| num | " << val.num(); break;
case vm_type::vm_str: std::clog << "| str | <0x" << std::hex << p
<< "> " << rawstr(val.str(), 16)
<< std::dec; break;
<< "> \"" << util::rawstr(val.str(), 16)
<< "\"" << std::dec; break;
case vm_type::vm_func: std::clog << "| func | <0x" << std::hex << p
<< std::dec << "> " << val.func();
break;
@ -191,7 +192,7 @@ void vm::trace_back() {
}
if (same) {
std::clog << " 0x" << std::hex
<< std::setw(6) << std::setfill('0')
<< std::setw(8) << std::setfill('0')
<< prev << std::dec << " "
<< same << " same call(s)\n";
same = 0;
@ -212,7 +213,7 @@ void vm::stack_info(const u64 limit = 16) {
for(u32 i = 0; i<limit && top>=bottom; ++i, --top) {
std::clog << " 0x" << std::hex
<< std::setw(6) << std::setfill('0')
<< std::setw(8) << std::setfill('0')
<< static_cast<u64>(top-bottom) << std::dec
<< " ";
value_info(top[0]);
@ -220,22 +221,22 @@ void vm::stack_info(const u64 limit = 16) {
}
void vm::register_info() {
std::clog << "\nregisters (" << (ngc.cort? "coroutine":"main")
<< ")\n" << std::hex
<< " [pc ] | pc | 0x" << ctx.pc << "\n"
<< " [global] | addr | 0x"
std::clog << "\nregisters (" << (ngc.cort? "coroutine":"main") << ")\n";
std::clog << std::hex
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
<< " [ global ] | addr | 0x"
<< reinterpret_cast<u64>(global) << "\n"
<< " [local ] | addr | 0x"
<< " [ local ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.localr) << "\n"
<< " [memr ] | addr | 0x"
<< " [ memr ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.memr) << "\n"
<< " [canary] | addr | 0x"
<< " [ canary ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.canary) << "\n"
<< " [top ] | addr | 0x"
<< " [ top ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.top) << "\n"
<< std::dec;
std::clog << " [funcr ] "; value_info(ctx.funcr);
std::clog << " [upval ] "; value_info(ctx.upvalr);
std::clog << " [ funcr ] "; value_info(ctx.funcr);
std::clog << " [ upval ] "; value_info(ctx.upvalr);
}
void vm::global_state() {
@ -245,7 +246,7 @@ void vm::global_state() {
std::clog << "\nglobal (0x" << std::hex
<< reinterpret_cast<u64>(global) << ")\n" << std::dec;
for(usize i = 0; i<global_size; ++i) {
std::clog << " 0x" << std::hex << std::setw(6)
std::clog << " 0x" << std::hex << std::setw(8)
<< std::setfill('0') << i << std::dec
<< " ";
value_info(global[i]);
@ -261,7 +262,7 @@ void vm::local_state() {
<< " <+" << static_cast<u64>(ctx.localr-ctx.stack)
<< ">)\n" << std::dec;
for(u32 i = 0; i<lsize; ++i) {
std::clog << " 0x" << std::hex << std::setw(6)
std::clog << " 0x" << std::hex << std::setw(8)
<< std::setfill('0') << i << std::dec
<< " ";
value_info(ctx.localr[i]);
@ -278,7 +279,7 @@ void vm::upvalue_state() {
std::clog << " -> upval[" << i << "]:\n";
auto& uv = upval[i].upval();
for(u32 j = 0; j<uv.size; ++j) {
std::clog << " 0x" << std::hex << std::setw(6)
std::clog << " 0x" << std::hex << std::setw(8)
<< std::setfill('0') << j << std::dec
<< " ";
value_info(uv[j]);
@ -391,7 +392,7 @@ std::string vm::type_name_string(const var& value) const {
}
void vm::die(const std::string& str) {
std::cerr << "\n[vm] error: " << str << "\n";
std::cerr << "[vm] error: " << str << "\n";
function_call_trace();
trace_back();
stack_info();

View File

@ -8,6 +8,7 @@
#include "nasal_import.h"
#include "nasal_gc.h"
#include "nasal_codegen.h"
#include "util/util.h"
#ifdef _MSC_VER
#pragma warning (disable:4244)
@ -50,6 +51,7 @@ protected:
/* limited mode, will not load unsafe system api if switched on */
bool flag_limited_mode = false;
protected:
/* vm initializing function */
void vm_init_enrty(const std::vector<std::string>&,
const std::vector<f64>&,
@ -60,6 +62,7 @@ protected:
const std::vector<std::string>&);
void context_and_global_init();
protected:
/* debug functions */
bool verbose = false;
void value_info(var&);
@ -190,20 +193,31 @@ public:
const std::vector<std::string>&); // get command line arguments
/* set detail report info flag */
void set_detail_report_info(bool flag) {verbose = flag;}
void set_detail_report_info(bool flag) {
verbose = flag;
}
/* set repl mode flag */
void set_repl_mode_flag(bool flag) {is_repl_mode = flag;}
void set_repl_mode_flag(bool flag) {
is_repl_mode = flag;
}
/* set repl output flag */
void set_allow_repl_output_flag(bool flag) {allow_repl_output = flag;}
void set_allow_repl_output_flag(bool flag) {
allow_repl_output = flag;
}
/* set limit mode flag */
void set_limit_mode_flag(bool flag) {flag_limited_mode = flag;}
void set_limit_mode_flag(bool flag) {
flag_limited_mode = flag;
}
};
inline bool vm::cond(var& val) {
if (val.is_num()) {
return val.num();
} else if (val.is_str()) {
const f64 num = str_to_num(val.str().c_str());
const f64 num = util::str_to_num(val.str().c_str());
return std::isnan(num)? !val.str().empty():num;
}
return false;
@ -320,7 +334,7 @@ inline void vm::o_lnot() {
case vm_type::vm_nil: ctx.top[0] = one; break;
case vm_type::vm_num: ctx.top[0] = val.num()? zero:one; break;
case vm_type::vm_str: {
const f64 num = str_to_num(val.str().c_str());
const f64 num = util::str_to_num(val.str().c_str());
if (std::isnan(num)) {
ctx.top[0] = var::num(static_cast<f64>(val.str().empty()));
} else {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -1,6 +1,12 @@
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#include "util/util.h"
#include <chrono>
#ifdef _WIN32
#include <windows.h>
#endif
namespace nasal {
var builtin_unsafe(context* ctx, gc* ngc) {
@ -41,7 +47,7 @@ var builtin_append(context* ctx, gc* ngc) {
var vec = local[1];
var elem = local[2];
if (!vec.is_vec()) {
return nas_err("append", "\"vec\" must be vector");
return nas_err("native::append", "\"vec\" must be vector");
}
auto& v = vec.vec().elems;
for(auto& i : elem.vec().elems) {
@ -55,7 +61,7 @@ var builtin_setsize(context* ctx, gc* ngc) {
var vec = local[1];
var size = local[2];
if (!vec.is_vec()) {
return nas_err("setsize", "\"vec\" must be vector");
return nas_err("native::setsize", "\"vec\" must be vector");
}
if (!size.is_num() || size.num()<0) {
return nil;
@ -89,10 +95,10 @@ var builtin_split(context* ctx, gc* ngc) {
var delimeter = local[1];
var str = local[2];
if (!delimeter.is_str()) {
return nas_err("split", "\"separator\" must be string");
return nas_err("native::split", "\"separator\" must be string");
}
if (!str.is_str()) {
return nas_err("split", "\"str\" must be string");
return nas_err("native::split", "\"str\" must be string");
}
const auto& deli = delimeter.str();
const auto& s = str.str();
@ -127,7 +133,7 @@ var builtin_split(context* ctx, gc* ngc) {
var builtin_rand(context* ctx, gc* ngc) {
auto val = ctx->localr[1];
if (!val.is_num() && !val.is_nil()) {
return nas_err("rand", "\"seed\" must be nil or number");
return nas_err("native::rand", "\"seed\" must be nil or number");
}
if (val.is_num()) {
srand(static_cast<u32>(val.num()));
@ -187,7 +193,7 @@ var builtin_num(context* ctx, gc* ngc) {
var builtin_pop(context* ctx, gc* ngc) {
auto val = ctx->localr[1];
if (!val.is_vec()) {
return nas_err("pop", "\"vec\" must be vector");
return nas_err("native::pop", "\"vec\" must be vector");
}
auto& vec = val.vec().elems;
if (vec.size()) {
@ -220,7 +226,7 @@ var builtin_size(context* ctx, gc* ngc) {
var builtin_time(context* ctx, gc* ngc) {
auto val = ctx->localr[1];
if (!val.is_num()) {
return nas_err("time", "\"begin\" must be number");
return nas_err("native::time", "\"begin\" must be number");
}
auto begin = static_cast<time_t>(val.num());
return var::num(static_cast<f64>(time(&begin)));
@ -241,7 +247,7 @@ var builtin_delete(context* ctx, gc* ngc) {
var hash = local[1];
var key = local[2];
if (!hash.is_hash()) {
return nas_err("delete", "\"hash\" must be hash");
return nas_err("native::delete", "\"hash\" must be hash");
}
if (!key.is_str()) {
return nil;
@ -255,7 +261,7 @@ var builtin_delete(context* ctx, gc* ngc) {
var builtin_keys(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (!hash.is_hash() && !hash.is_map()) {
return nas_err("keys", "\"hash\" must be hash");
return nas_err("native::keys", "\"hash\" must be hash");
}
// avoid being sweeped
auto res = ngc->temp = ngc->alloc(vm_type::vm_vec);
@ -274,7 +280,7 @@ var builtin_keys(context* ctx, gc* ngc) {
}
var builtin_die(context* ctx, gc* ngc) {
return nas_err("error", ctx->localr[1].to_str());
return nas_err("native::error", ctx->localr[1].to_str());
}
var builtin_find(context* ctx, gc* ngc) {
@ -311,18 +317,18 @@ var builtin_substr(context* ctx, gc* ngc) {
var beg = local[2];
var len = local[3];
if (!str.is_str()) {
return nas_err("substr", "\"str\" must be string");
return nas_err("native::substr", "\"str\" must be string");
}
if (!beg.is_num() || beg.num()<0) {
return nas_err("substr", "\"begin\" should be number >= 0");
return nas_err("native::substr", "\"begin\" should be number >= 0");
}
if (!len.is_num() || len.num()<0) {
return nas_err("substr", "\"length\" should be number >= 0");
return nas_err("native::substr", "\"length\" should be number >= 0");
}
auto begin = static_cast<usize>(beg.num());
auto length = static_cast<usize>(len.num());
if (begin>=str.str().length()) {
return nas_err("susbtr", "begin index out of range: "+std::to_string(begin));
return nas_err("native::susbtr", "begin index out of range: "+std::to_string(begin));
}
return ngc->newstr(str.str().substr(begin, length));
}
@ -342,10 +348,10 @@ var builtin_left(context* ctx, gc* ngc) {
var len = local[2];
if (!str.is_str()) {
return nas_err("left", "\"string\" must be string");
return nas_err("native::left", "\"string\" must be string");
}
if (!len.is_num()) {
return nas_err("left", "\"length\" must be number");
return nas_err("native::left", "\"length\" must be number");
}
if (len.num()<0) {
return ngc->newstr("");
@ -359,10 +365,10 @@ var builtin_right(context* ctx, gc* ngc) {
var len = local[2];
if (!str.is_str()) {
return nas_err("right", "\"string\" must be string");
return nas_err("native::right", "\"string\" must be string");
}
if (!len.is_num()) {
return nas_err("right", "\"length\" must be number");
return nas_err("native::right", "\"length\" must be number");
}
i32 length = static_cast<i32>(len.num());
@ -382,7 +388,7 @@ var builtin_cmp(context* ctx, gc* ngc) {
var a = local[1];
var b = local[2];
if (!a.is_str() || !b.is_str()) {
return nas_err("cmp", "\"a\" and \"b\" must be string");
return nas_err("native::cmp", "\"a\" and \"b\" must be string");
}
return var::num(static_cast<f64>(strcmp(
a.str().c_str(),
@ -425,7 +431,7 @@ var builtin_char(context* ctx, gc* ngc) {
var builtin_values(context* ctx, gc* ngc) {
auto hash = ctx->localr[1];
if (!hash.is_hash() && !hash.is_map()) {
return nas_err("values", "\"hash\" must be hash or namespace");
return nas_err("native::values", "\"hash\" must be hash or namespace");
}
auto vec = ngc->alloc(vm_type::vm_vec);
auto& v = vec.vec().elems;
@ -459,11 +465,11 @@ var builtin_sleep(context* ctx, gc* ngc) {
}
var builtin_platform(context* ctx, gc* ngc) {
return ngc->newstr(get_platform());
return ngc->newstr(util::get_platform());
}
var builtin_arch(context* ctx, gc* ngc) {
return ngc->newstr(get_arch());
return ngc->newstr(util::get_arch());
}
// md5 related functions
@ -560,7 +566,7 @@ std::string md5(const std::string& src) {
var builtin_md5(context* ctx, gc* ngc) {
auto str = ctx->localr[1];
if (!str.is_str()) {
return nas_err("md5", "\"str\" must be string");
return nas_err("native::md5", "\"str\" must be string");
}
return ngc->newstr(md5(str.str()));
}
@ -700,7 +706,7 @@ var builtin_logtime(context* ctx, gc* ngc) {
var builtin_ghosttype(context* ctx, gc* ngc) {
auto arg = ctx->localr[1];
if (!arg.is_ghost()) {
return nas_err("ghosttype", "this is not a ghost object.");
return nas_err("native::ghosttype", "this is not a ghost object.");
}
const auto& name = arg.ghost().get_ghost_name();
@ -717,6 +723,15 @@ var builtin_ghosttype(context* ctx, gc* ngc) {
return ngc->newstr(name);
}
var builtin_set_utf8_output(context* ctx, gc* ngc) {
#ifdef _WIN32
// allow 65001 code page
SetConsoleOutputCP(CP_UTF8);
#endif
// do nothing on other platforms
return nil;
}
nasal_builtin_table builtin[] = {
{"__print", builtin_print},
{"__println", builtin_println},
@ -763,6 +778,7 @@ nasal_builtin_table builtin[] = {
{"__gcinfo", builtin_gcinfo},
{"__logtime", builtin_logtime},
{"__ghosttype", builtin_ghosttype},
{"__set_utf8_output", builtin_set_utf8_output},
{nullptr, nullptr}
};

View File

@ -81,6 +81,9 @@ var builtin_gcinfo(context*, gc*);
var builtin_logtime(context*, gc*);
var builtin_ghosttype(context*, gc*);
// only useful on windows platform
var builtin_set_utf8_output(context*, gc*);
// register builtin function's name and it's address here in this table below
// this table must end with {nullptr, nullptr}
struct nasal_builtin_table {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#ifdef _WIN32
#include <windows.h>

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -1,5 +1,7 @@
#include "natives/io_lib.h"
#include "util/fs.h"
#include <fstream>
#include <sys/stat.h>
namespace nasal {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#ifndef _MSC_VER
#include <unistd.h>

View File

@ -1,4 +1,5 @@
#include "natives/json_lib.h"
#include "util/util.h"
#include <iostream>
#include <cstring>
@ -170,7 +171,7 @@ void json::next() {
} else if (text[ptr]!=' ' && text[ptr]!='\t' && text[ptr]!='\r') {
error_info() += "json::parse: line " + std::to_string(line);
error_info() += ": invalid character `0x";
error_info() += char_to_hex(text[ptr]);
error_info() += util::char_to_hex(text[ptr]);
error_info() += "`\n";
}
++ptr;
@ -253,7 +254,7 @@ void json::vector_member(nas_vec& vec, gc* ngc) {
vec.elems.push_back(ngc->newstr(this_token.content));
next();
} else if (this_token.type==json_token_type::tok_num) {
vec.elems.push_back(var::num(str_to_num(this_token.content.c_str())));
vec.elems.push_back(var::num(util::str_to_num(this_token.content.c_str())));
next();
}
}
@ -292,7 +293,7 @@ void json::hash_member(nas_hash& hash, gc* ngc) {
hash.elems.insert({name, ngc->newstr(this_token.content)});
next();
} else if (this_token.type==json_token_type::tok_num) {
hash.elems.insert({name, var::num(str_to_num(this_token.content.c_str()))});
hash.elems.insert({name, var::num(util::str_to_num(this_token.content.c_str()))});
next();
}
}

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -4,7 +4,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
namespace nasal {

View File

@ -2,7 +2,7 @@
#include "nasal.h"
#include "nasal_gc.h"
#include "natives/nasal_builtin.h"
#include "natives/builtin.h"
#ifndef _MSC_VER
#include <unistd.h>

View File

@ -47,12 +47,12 @@ bool repl::check_need_more_input() {
i64 in_brace = 0;
for(const auto& t : nasal_lexer->result()) {
switch(t.type) {
case tok::lcurve: ++in_curve; break;
case tok::rcurve: --in_curve; break;
case tok::lbracket: ++in_bracket; break;
case tok::rbracket: --in_bracket; break;
case tok::lbrace: ++in_brace; break;
case tok::rbrace: --in_brace; break;
case tok::tk_lcurve: ++in_curve; break;
case tok::tk_rcurve: --in_curve; break;
case tok::tk_lbracket: ++in_bracket; break;
case tok::tk_rbracket: --in_bracket; break;
case tok::tk_lbrace: ++in_brace; break;
case tok::tk_rbrace: --in_brace; break;
default: break;
}
}

43
src/util/fs.cpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <io.h>
#endif
#ifdef _MSC_VER
#pragma warning (disable:4996)
#endif
#include <sys/stat.h>
#include "util/util.h"
#include "util/fs.h"
#include "nasal.h"
namespace nasal::fs {
path& path::operator/(const path& another) {
this->file_system_path += util::is_windows()? "\\":"/";
this->file_system_path += another.file_system_path;
return *this;
}
bool exists(const path& file_path) {
#ifdef _MSC_VER
#define F_OK 0 // fuck msc
#endif
return access(file_path.c_str(), F_OK)==0;
}
bool is_regular(const path& file_path) {
#ifdef _MSC_VER
#define S_ISREG(m) (((m)&0xF000)==0x8000)
#endif
struct stat buffer;
if (stat(file_path.c_str(), &buffer)!=0) {
return false;
}
return S_ISREG(buffer.st_mode);
}
}

27
src/util/fs.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <cstring>
#include <sstream>
namespace nasal::fs {
class path {
private:
std::string file_system_path;
public:
path(const path&) = default;
path(const std::string& file_path): file_system_path(file_path) {}
path& operator/(const path&);
const char* c_str() const {
return file_system_path.c_str();
}
const std::string& str() const {
return file_system_path;
}
};
bool exists(const path&);
bool is_regular(const path&);
}

View File

@ -1,17 +1,8 @@
#include "nasal.h"
#include "util/util.h"
#ifndef _MSC_VER
#include <unistd.h>
#else
#include <io.h>
#endif
#include <sys/stat.h>
#include <cmath>
#ifdef _MSC_VER
#pragma warning (disable:4996)
#endif
namespace nasal {
namespace nasal::util {
bool is_windows() {
#if defined(_WIN32) || defined(_WIN64)
@ -105,7 +96,7 @@ const char* get_platform() {
} else if (is_macos()) {
return "macOS";
}
return "unknown platform";
return "unknown";
}
const char* get_arch() {
@ -126,7 +117,57 @@ const char* get_arch() {
} else if (is_superh()) {
return "superh";
}
return "unknown arch";
return "unknown";
}
u32 utf8_hdchk(const char head) {
// RFC-2279 but now we use RFC-3629 so nbytes is less than 4
const auto c = static_cast<u8>(head);
if ((c>>5)==0x06) { // 110x xxxx (10xx xxxx)^1
return 1;
}
if ((c>>4)==0x0e) { // 1110 xxxx (10xx xxxx)^2
return 2;
}
if ((c>>3)==0x1e) { // 1111 0xxx (10xx xxxx)^3
return 3;
}
return 0;
}
std::string char_to_hex(const char c) {
const char hextbl[] = "0123456789abcdef";
return {hextbl[(c&0xf0)>>4], hextbl[c&0x0f]};
}
std::string rawstr(const std::string& str, const usize maxlen) {
std::string ret("");
for(auto i : str) {
// windows doesn't output unicode normally, so we output the hex
if (util::is_windows() && i<=0) {
ret += "\\x" + char_to_hex(i);
continue;
}
switch(i) {
case '\0': ret += "\\0"; break;
case '\a': ret += "\\a"; break;
case '\b': ret += "\\b"; break;
case '\t': ret += "\\t"; break;
case '\n': ret += "\\n"; break;
case '\v': ret += "\\v"; break;
case '\f': ret += "\\f"; break;
case '\r': ret += "\\r"; break;
case '\033':ret += "\\e"; break;
case '\"': ret += "\\\""; break;
case '\'': ret += "\\\'"; break;
case '\\': ret += "\\\\"; break;
default: ret += i; break;
}
}
if (maxlen && ret.length()>maxlen) {
ret = ret.substr(0, maxlen)+"...";
}
return ret;
}
f64 hex_to_f64(const char* str) {
@ -227,82 +268,4 @@ f64 str_to_num(const char* str) {
return negative? -res:res;
}
i32 utf8_hdchk(const char head) {
// RFC-2279 but now we use RFC-3629 so nbytes is less than 4
const auto c = static_cast<u8>(head);
if ((c>>5)==0x06) { // 110x xxxx (10xx xxxx)^1
return 1;
}
if ((c>>4)==0x0e) { // 1110 xxxx (10xx xxxx)^2
return 2;
}
if ((c>>3)==0x1e) { // 1111 0xxx (10xx xxxx)^3
return 3;
}
return 0;
}
std::string char_to_hex(const char c) {
const char hextbl[] = "0123456789abcdef";
return {hextbl[(c&0xf0)>>4], hextbl[c&0x0f]};
}
std::string rawstr(const std::string& str, const usize maxlen) {
std::string ret("");
for(auto i : str) {
// windows doesn't output unicode normally, so we output the hex
if (is_windows() && i<=0) {
ret += "\\x" + char_to_hex(i);
continue;
}
switch(i) {
case '\0': ret += "\\0"; break;
case '\a': ret += "\\a"; break;
case '\b': ret += "\\b"; break;
case '\t': ret += "\\t"; break;
case '\n': ret += "\\n"; break;
case '\v': ret += "\\v"; break;
case '\f': ret += "\\f"; break;
case '\r': ret += "\\r"; break;
case '\033':ret += "\\e"; break;
case '\"': ret += "\\\""; break;
case '\'': ret += "\\\'"; break;
case '\\': ret += "\\\\"; break;
default: ret += i; break;
}
}
if (maxlen && ret.length()>maxlen) {
ret = ret.substr(0, maxlen)+"...";
}
return ret;
}
namespace fs {
path& path::operator/(const path& another) {
this->file_system_path += is_windows()? "\\":"/";
this->file_system_path += another.file_system_path;
return *this;
}
bool exists(const path& file_path) {
#ifdef _MSC_VER
#define F_OK 0 // fuck msc
#endif
return access(file_path.c_str(), F_OK)==0;
}
bool is_regular(const path& file_path) {
#ifdef _MSC_VER
#define S_ISREG(m) (((m)&0xF000)==0x8000)
#endif
struct stat buffer;
if (stat(file_path.c_str(), &buffer)!=0) {
return false;
}
return S_ISREG(buffer.st_mode);
}
}
}
}

73
src/util/util.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include "nasal.h"
#ifdef _WIN32
#include <windows.h>
#endif
#include <cstring>
#include <sstream>
namespace nasal::util {
bool is_windows();
bool is_linux();
bool is_macos();
bool is_x86();
bool is_amd64();
bool is_x86_64();
bool is_arm();
bool is_aarch64();
bool is_ia64();
bool is_powerpc();
bool is_superh();
const char* get_platform();
const char* get_arch();
u32 utf8_hdchk(const char);
std::string char_to_hex(const char);
std::string rawstr(const std::string&, const usize maxlen = 0);
f64 hex_to_f64(const char*);
f64 oct_to_f64(const char*);
// we have the same reason not using atof here
// just as andy's interpreter does.
// it is not platform independent, and may have strange output.
// so we write a new function here to convert str to number manually.
// but this also makes 0.1+0.2==0.3,
// not another result that you may get in other languages.
f64 dec_to_f64(const char*);
f64 str_to_num(const char*);
class windows_code_page_manager {
private:
u32 code_page;
public:
windows_code_page_manager() {
#ifdef _WIN32
code_page = GetConsoleOutputCP();
#endif
}
void set_utf8_output() {
#ifdef _WIN32
// store previous code page
code_page = GetConsoleOutputCP();
// allow 65001 code page
SetConsoleOutputCP(CP_UTF8);
#endif
}
void restore_code_page() {
#ifdef _WIN32
// restore previous code page
SetConsoleOutputCP(code_page);
#endif
}
};
}

View File

@ -1,13 +1,35 @@
# runtime.nas
# 2023 by ValKmjolnir
# runtime gives us some functions that we could manage it manually.
# command line arguments
var argv = func() {
return globals.arg;
}
var gc = {
extend: func(type) {return __gcextd;},
info: func() {return __gcinfo;}
};
# runtime.nas
# 2023 by ValKmjolnir
# runtime gives us some functions that we could manage it manually.
# command line arguments
var argv = func() {
return globals.arg;
}
var _gc_extend = func(type) {
return __gcextd;
}
var gc = {
extend: func(type, times = 1) {
if (times<=0) {
return nil;
}
if (times>16) {
times = 16;
}
for(var i = 0; i<times; i+=1) {
_gc_extend(type);
}
return nil;
},
info: func() {return __gcinfo;}
};
var windows = {
set_utf8_output: func() {
return __set_utf8_output;
}
};

View File

@ -1,7 +1,24 @@
use std.padding;
use std.process_bar;
use std.os;
use std.unix;
use std.runtime;
var table_character_set = [
"─", "━", "│", "┃", "╌", "╍", "╎", "╏", "┄", "┅",
"┆", "┇", "┈", "┉", "┊", "┋", "┌", "┍", "┎", "┏",
"┐", "┑", "┒", "┓", "└", "┕", "┖", "┗", "┘", "┙",
"┚", "┛", "├", "┝", "┞", "┟", "┠", "┡", "┢", "┣",
"┤", "┥", "┦", "┧", "┨", "┩", "┪", "┫", "┬", "┭",
"┮", "┯", "┰", "┱", "┲", "┳", "┴", "┵", "┶", "┷",
"┸", "┹", "┺", "┻", "┼", "┽", "┾", "┿", "╀", "╁",
"╂", "╃", "╄", "╅", "╆", "╇", "╈", "╉", "╊", "╋",
"╪", "╫", "╬", "═", "║", "╒", "╓", "╔", "╕", "╖",
"╗", "╘", "╙", "╚", "╛", "╜", "╝", "╞", "╟", "╠",
"╡", "╢", "╣", "╤", "╥", "╦", "╧", "╨", "╬", "╩",
"┷", "┳", "⊥", "﹃", "﹄", "╮", "╭", "╯", "╰", ""
];
var selection_box = ["○", "◉", "☐", "▣"];
var char_ttf=[
[" "," "," "," "," "," "],
@ -196,9 +213,7 @@ var ansi_escape_sequence = func() {
}
# enable unicode
if (os.platform()=="windows") {
system("chcp 65001");
}
runtime.windows.set_utf8_output();
trans_ttf("just for test");
trans_ttf(" ValKmjolnir ");

View File

@ -1,252 +1,250 @@
# ray tracing example
# modified from Artem Yashin's project Console3D
# MIT License
# Copyright (c) 2021 Artem Yashin
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
use module.libmat;
use std.runtime;
use std.math;
func() {
# allocate more spaces
for(var i = 0; i<10; i+=1) {
runtime.gc.extend("str");
runtime.gc.extend("vec");
}
}();
var (max,min,sqrt,sin,cos,abs)=(
math.max,
math.min,
math.sqrt,
math.sin,
math.cos,
math.abs
);
var (vec2,vec3)=(
libmat.vec2.new,
libmat.vec3.new
);
var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=(
libmat.vec2.add,
libmat.vec2.sub,
libmat.vec2.mul,
libmat.vec2.div,
libmat.vec2.len
);
var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=(
libmat.vec3.add,
libmat.vec3.sub,
libmat.vec3.mul,
libmat.vec3.div,
libmat.vec3.neg,
libmat.vec3.norm,
libmat.vec3.len,
libmat.vec3.dot
);
var (rotateX,rotateY,rotateZ)=(
libmat.vec3.rx,
libmat.vec3.ry,
libmat.vec3.rz,
);
var use_raw = func() {
vec2 = func(x,y) {return [x,y];}
vec2add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1]];}
vec2sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1]];}
vec2mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1]];}
vec2div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1]];}
vec3 = func(x,y,z) {return [x,y,z];}
vec3add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];}
vec3sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];}
vec3mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];}
vec3div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];}
vec3neg = func(v) {return [-v[0],-v[1],-v[2]];}
vec2len = func(v) {var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);}
vec3len = func(v) {var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);}
vec3norm = func(v) {var t=vec3len(v); return vec3div(v,[t,t,t]);}
vec3dot = func(a,b) {return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
rotateX = func(a,angle) {return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];}
rotateY = func(a,angle) {return [a[0]*cos(angle)-a[2]*sin(angle),a[1],a[0]*sin(angle)+a[2]*cos(angle)];}
rotateZ = func(a,angle) {return [a[0]*cos(angle)-a[1]*sin(angle),a[0]*sin(angle)+a[1]*cos(angle),a[2]];}
}
var clamp = func(value,_min,_max) {
return max(min(value,_max),_min);
}
var sign = func(a) {
return (0<a)-(a<0);
}
var step = func(edge,x) {
return x>edge;
}
var vec3abs = func(v) {
return [abs(v[0]),abs(v[1]),abs(v[2])];
}
var vec3sign = func(v) {
return [sign(v[0]),sign(v[1]),sign(v[2])];
}
var vec3step = func(edge,v) {
return [step(edge[0],v[0]),step(edge[1],v[1]),step(edge[2],v[2])];
}
var vec3reflect = func(rd,n) {
var d=vec3dot(n,rd);
return vec3sub(rd,vec3mul(n,vec3mul([2,2,2],[d,d,d])));
}
var sphere = func(ro,rd,r) {
var b=vec3dot(ro,rd);
var c=vec3dot(ro,ro)-r*r;
var h=b*b-c;
if (h<0.0) return [-1.0,-1.0];
h=sqrt(h);
return [-b-h,-b+h];
}
var box = func(ro,rd,boxSize,outNormal) {
var m=vec3div([1.0,1.0,1.0],rd);
var n=vec3mul(m,ro);
var k=vec3mul(vec3abs(m),boxSize);
var t1=vec3sub(vec3neg(n),k);
var t2=vec3add(vec3neg(n),k);
var tN=max(max(t1[0],t1[1]),t1[2]);
var tF=min(min(t2[0],t2[1]),t2[2]);
if (tN>tF or tF<0.0) return [-1.0,-1.0];
var yzx=[t1[1],t1[2],t1[0]];
var zxy=[t1[2],t1[0],t1[1]];
var tmp=vec3mul(vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx,t1)),vec3step(zxy,t1));
outNormal[0]=tmp[0];
outNormal[1]=tmp[1];
outNormal[2]=tmp[2];
return [tN, tF];
}
var plane = func(ro,rd,p,w) {
return -(vec3dot(ro,p)+w)/vec3dot(rd,p);
}
var main = func(frame) {
var height=15*2;
var width=int(height*1/0.618)*2;
var aspect=width/height;
var pixelAspect=11.0/24.0;
var gradient=split(""," .:!/r(l1Z4H9W8$");
var gradientSize=size(gradient)-1;
var screen=[];
setsize(screen,width*height);
var light=vec3norm([-0.5,0.5,-1.0]);
var spherePos=[0,3,0];
var vec2_2_2=[2,2];
var vec2_1_1=[1,1];
var vec3_000=[0,0,0];
var vec3_00n1=[0,0,-1];
var vec3_111=[1,1,1];
print("\e[2J");
var stamp=maketimestamp();
for(var t=0;t<frame;t+=1) {
stamp.stamp();
for(var i=0;i<width;i+=1) {
for(var j=0;j<height;j+=1) {
var uv=vec2sub(vec2mul(vec2div([i,j],[width,height]),vec2_2_2),vec2_1_1);
uv[0]*=aspect*pixelAspect;
var ro=[-6,0,0];
var rd=vec3norm([2,uv[0],uv[1]]);
ro=rotateY(ro,0.25);
rd=rotateY(rd,0.25);
ro=rotateZ(ro,t*0.03);
rd=rotateZ(rd,t*0.03);
var diff=1;
for (var k=0;k<5;k+=1) {
var minIt=99999;
var intersection=sphere(vec3sub(ro,spherePos),rd,1);
var n=vec3_000;
var albedo=1;
if (intersection[0]>0) {
var itPoint=vec3add(vec3sub(ro,spherePos),vec3mul(rd,[intersection[0],intersection[0],intersection[0]]));
minIt=intersection[0];
n=vec3norm(itPoint);
}
var boxN=[0,0,0];
intersection=box(ro,rd,vec3_111,boxN);
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=boxN;
}
var tmp=plane(ro,rd,vec3_00n1,1);
intersection=[tmp,tmp];
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=vec3_00n1;
albedo=0.5;
}
if (minIt<99999) {
diff*=(vec3dot(n,light)*0.5+0.5)*albedo;
ro=vec3add(ro,vec3mul(rd,[minIt-0.01,minIt-0.01,minIt-0.01]));
rd=vec3reflect(rd,n);
}
else break;
}
var color=int(diff*20);
color=clamp(color,0,gradientSize);
screen[i+j*width]=gradient[color];
}
}
var s="";
forindex(var index;screen) {
s~=screen[index];
if (index+1-int((index+1)/width)*width==0)
s~="\n";
}
var elt=stamp.elapsedMSec()/1000;
print("\e[H",int(1/elt)," fps \n",s);
}
}
var st=maketimestamp();
var run=[0,0];
var frame=1e3;
if (size(runtime.argv())!=0) {
var n=num(runtime.argv()[0]);
if (!math.isnan(n)) {
frame=n;
}
}
st.stamp();
main(frame);
run[0]=st.elapsedMSec();
use_raw();
st.stamp();
main(frame);
run[1]=st.elapsedMSec();
println("test 0: ",run[0]/1000,"s ",frame*1000/run[0]," fps");
# ray tracing example
# modified from Artem Yashin's project Console3D
# MIT License
# Copyright (c) 2021 Artem Yashin
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
use module.libmat;
use std.runtime;
use std.math;
func() {
# allocate more spaces
runtime.gc.extend("str", 8);
runtime.gc.extend("vec", 8);
}();
var (max,min,sqrt,sin,cos,abs)=(
math.max,
math.min,
math.sqrt,
math.sin,
math.cos,
math.abs
);
var (vec2,vec3)=(
libmat.vec2.new,
libmat.vec3.new
);
var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=(
libmat.vec2.add,
libmat.vec2.sub,
libmat.vec2.mul,
libmat.vec2.div,
libmat.vec2.len
);
var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=(
libmat.vec3.add,
libmat.vec3.sub,
libmat.vec3.mul,
libmat.vec3.div,
libmat.vec3.neg,
libmat.vec3.norm,
libmat.vec3.len,
libmat.vec3.dot
);
var (rotateX,rotateY,rotateZ)=(
libmat.vec3.rx,
libmat.vec3.ry,
libmat.vec3.rz,
);
var use_raw = func() {
vec2 = func(x,y) {return [x,y];}
vec2add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1]];}
vec2sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1]];}
vec2mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1]];}
vec2div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1]];}
vec3 = func(x,y,z) {return [x,y,z];}
vec3add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];}
vec3sub = func(v1,v2) {return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];}
vec3mul = func(v1,v2) {return [v1[0]*v2[0],v1[1]*v2[1],v1[2]*v2[2]];}
vec3div = func(v1,v2) {return [v1[0]/v2[0],v1[1]/v2[1],v1[2]/v2[2]];}
vec3neg = func(v) {return [-v[0],-v[1],-v[2]];}
vec2len = func(v) {var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);}
vec3len = func(v) {var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);}
vec3norm = func(v) {var t=vec3len(v); return vec3div(v,[t,t,t]);}
vec3dot = func(a,b) {return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
rotateX = func(a,angle) {return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];}
rotateY = func(a,angle) {return [a[0]*cos(angle)-a[2]*sin(angle),a[1],a[0]*sin(angle)+a[2]*cos(angle)];}
rotateZ = func(a,angle) {return [a[0]*cos(angle)-a[1]*sin(angle),a[0]*sin(angle)+a[1]*cos(angle),a[2]];}
}
var clamp = func(value,_min,_max) {
return max(min(value,_max),_min);
}
var sign = func(a) {
return (0<a)-(a<0);
}
var step = func(edge,x) {
return x>edge;
}
var vec3abs = func(v) {
return [abs(v[0]),abs(v[1]),abs(v[2])];
}
var vec3sign = func(v) {
return [sign(v[0]),sign(v[1]),sign(v[2])];
}
var vec3step = func(edge,v) {
return [step(edge[0],v[0]),step(edge[1],v[1]),step(edge[2],v[2])];
}
var vec3reflect = func(rd,n) {
var d=vec3dot(n,rd);
return vec3sub(rd,vec3mul(n,vec3mul([2,2,2],[d,d,d])));
}
var sphere = func(ro,rd,r) {
var b=vec3dot(ro,rd);
var c=vec3dot(ro,ro)-r*r;
var h=b*b-c;
if (h<0.0) return [-1.0,-1.0];
h=sqrt(h);
return [-b-h,-b+h];
}
var box = func(ro,rd,boxSize,outNormal) {
var m=vec3div([1.0,1.0,1.0],rd);
var n=vec3mul(m,ro);
var k=vec3mul(vec3abs(m),boxSize);
var t1=vec3sub(vec3neg(n),k);
var t2=vec3add(vec3neg(n),k);
var tN=max(max(t1[0],t1[1]),t1[2]);
var tF=min(min(t2[0],t2[1]),t2[2]);
if (tN>tF or tF<0.0) return [-1.0,-1.0];
var yzx=[t1[1],t1[2],t1[0]];
var zxy=[t1[2],t1[0],t1[1]];
var tmp=vec3mul(vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx,t1)),vec3step(zxy,t1));
outNormal[0]=tmp[0];
outNormal[1]=tmp[1];
outNormal[2]=tmp[2];
return [tN, tF];
}
var plane = func(ro,rd,p,w) {
return -(vec3dot(ro,p)+w)/vec3dot(rd,p);
}
var main = func(frame) {
var height=15*2;
var width=int(height*1/0.618)*2;
var aspect=width/height;
var pixelAspect=11.0/24.0;
var gradient=split(""," .:!/r(l1Z4H9W8$");
var gradientSize=size(gradient)-1;
var screen=[];
setsize(screen,width*height);
var light=vec3norm([-0.5,0.5,-1.0]);
var spherePos=[0,3,0];
var vec2_2_2=[2,2];
var vec2_1_1=[1,1];
var vec3_000=[0,0,0];
var vec3_00n1=[0,0,-1];
var vec3_111=[1,1,1];
print("\e[2J");
var stamp=maketimestamp();
for(var t=0;t<frame;t+=1) {
stamp.stamp();
for(var i=0;i<width;i+=1) {
for(var j=0;j<height;j+=1) {
var uv=vec2sub(vec2mul(vec2div([i,j],[width,height]),vec2_2_2),vec2_1_1);
uv[0]*=aspect*pixelAspect;
var ro=[-6,0,0];
var rd=vec3norm([2,uv[0],uv[1]]);
ro=rotateY(ro,0.25);
rd=rotateY(rd,0.25);
ro=rotateZ(ro,t*0.03);
rd=rotateZ(rd,t*0.03);
var diff=1;
for (var k=0;k<5;k+=1) {
var minIt=99999;
var intersection=sphere(vec3sub(ro,spherePos),rd,1);
var n=vec3_000;
var albedo=1;
if (intersection[0]>0) {
var itPoint=vec3add(vec3sub(ro,spherePos),vec3mul(rd,[intersection[0],intersection[0],intersection[0]]));
minIt=intersection[0];
n=vec3norm(itPoint);
}
var boxN=[0,0,0];
intersection=box(ro,rd,vec3_111,boxN);
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=boxN;
}
var tmp=plane(ro,rd,vec3_00n1,1);
intersection=[tmp,tmp];
if (intersection[0]>0 and intersection[0]<minIt) {
minIt=intersection[0];
n=vec3_00n1;
albedo=0.5;
}
if (minIt<99999) {
diff*=(vec3dot(n,light)*0.5+0.5)*albedo;
ro=vec3add(ro,vec3mul(rd,[minIt-0.01,minIt-0.01,minIt-0.01]));
rd=vec3reflect(rd,n);
}
else break;
}
var color=int(diff*20);
color=clamp(color,0,gradientSize);
screen[i+j*width]=gradient[color];
}
}
var s="";
forindex(var index;screen) {
s~=screen[index];
if (index+1-int((index+1)/width)*width==0)
s~="\n";
}
var elt=stamp.elapsedMSec()/1000;
print("\e[H",int(1/elt)," fps \n",s);
}
}
var st=maketimestamp();
var run=[0,0];
var frame=1e3;
if (size(runtime.argv())!=0) {
var n=num(runtime.argv()[0]);
if (!math.isnan(n)) {
frame=n;
}
}
st.stamp();
main(frame);
run[0]=st.elapsedMSec();
use_raw();
st.stamp();
main(frame);
run[1]=st.elapsedMSec();
println("test 0: ",run[0]/1000,"s ",frame*1000/run[0]," fps");
println("test 1: ",run[1]/1000,"s ",frame*1000/run[1]," fps");

View File

@ -4,9 +4,10 @@ use std.coroutine;
use std.process_bar;
use std.padding;
use std.os;
use std.runtime;
if (os.platform()=="windows") {
system("chcp 65001");
runtime.windows.set_utf8_output();
system("color");
}

View File

@ -1,4 +1,4 @@
use std.os;
use std.runtime;
use std.io;
use std.unix;
@ -35,7 +35,7 @@ var prt = func(s,path) {
}
# enable unicode
if (os.platform()=="windows")
system("chcp 65001");
runtime.windows.set_utf8_output();
println("\e[33m[",unix.getcwd(),"]\e[36m>\e[0m");
prt([""],".");

View File

@ -1,7 +1,7 @@
use test.md5_self;
use std.process_bar;
use std.file;
use std.os;
use std.runtime;
use std.io;
use std.math;
@ -47,6 +47,12 @@ var compare = func() {
};
}();
var add_all_cpp_files = func(vec, path) {
foreach(var p; file.find_all_files_with_extension(path,"cpp","h")) {
append(vec, path~"/"~p);
}
}
var filechecksum = func() {
var files = [];
foreach(var p; file.find_all_files_with_extension("./test","nas")) {
@ -61,9 +67,11 @@ var filechecksum = func() {
foreach(var p; file.find_all_files_with_extension(".","md")) {
append(files, "./"~p);
}
foreach(var p; file.find_all_files_with_extension("./src","cpp","h")) {
append(files, "./src/"~p);
}
add_all_cpp_files(files, "./src");
add_all_cpp_files(files, "./src/cli");
add_all_cpp_files(files, "./src/natives");
add_all_cpp_files(files, "./src/repl");
add_all_cpp_files(files, "./src/util");
foreach(var p; file.find_all_files_with_extension("./doc","md")) {
append(files, "./doc/"~p);
}
@ -101,8 +109,6 @@ var randomchecksum = func() {
}
}
if (os.platform()=="windows") {
system("chcp 65001");
}
runtime.windows.set_utf8_output();
filechecksum();
randomchecksum();

View File

@ -11,7 +11,7 @@ var is_windows_platform=os.platform()=="windows";
var is_macos_platform=os.platform()=="macOS";
if (is_windows_platform) {
system("chcp 65001");
runtime.windows.set_utf8_output();
}
var cpu_stat = func() {

View File

@ -1,4 +1,5 @@
use std.os;
use std.runtime;
var code=[
[1,1,1,1,1,1,1,0,1,0,0,1,1,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1],
[1,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,0,0,1],
@ -32,8 +33,7 @@ var code=[
];
# enable unicode
if (os.platform()=="windows")
system("chcp 65001");
runtime.windows.set_utf8_output();
var texture=[" ","██"];
for(var i=0;i<size(code);i+=1) {
for(var j=0;j<size(code[i]);j+=1)

View File

@ -2,7 +2,6 @@ use module.libkey;
use std.list;
use std.runtime;
use std.coroutine;
use std.os;
use std.unix;
var game = func(x,y) {
@ -130,8 +129,7 @@ var co=coroutine.create(func() {
var main = func(argv) {
var should_skip=(size(argv)!=0 and argv[0]=="--skip");
# enable unicode
if (os.platform()=="windows")
system("chcp 65001");
runtime.windows.set_utf8_output();
print("\ec");
var g=game(15,10);

View File

@ -1,6 +1,5 @@
use module.libkey;
use std.runtime;
use std.os;
use std.unix;
var color=[
@ -277,9 +276,9 @@ var mapgen = func(mapx,mapy) {
var main = func(argv) {
var should_skip=(size(argv)!=0 and argv[0]=="--skip");
var init_counter=should_skip?5:30;
# windows use chcp 65001 to output unicode
if (os.platform()=="windows")
system("chcp 65001");
# windows use 65001 to output unicode
runtime.windows.set_utf8_output();
print(
"\ec\e[1:1H",

View File

@ -1,11 +1,16 @@
use std.runtime;
# do nothing if platform is not windows
runtime.windows.set_utf8_output();
var unicode测试 = func() {
var 输出=print;
var 测试成功=[
"unicode: utf-8支持测试成功",
"目前仅支持utf-8以及ascii格式文件",
"注意: windows系统请开启chcp 65001代码页"
"unicode: utf-8 支持测试成功",
"目前仅支持 utf-8 以及 ascii 格式文件",
"注意: windows 系统请开启 chcp 65001 代码页"
];
foreach(var 内容;测试成功)
foreach(var 内容; 测试成功)
输出(内容~"\n");
}
@ -41,10 +46,10 @@ var emoji测试 = func() {
🍾:🍾,
🐘:🐘
};
foreach(var 📄;📁)
💻(📄,🎤);
foreach(var 📄;keys(🗄️))
💻(📄,🗄️[📄],🎤);
foreach(var 📄; 📁)
💻(📄, 🎤);
foreach(var 📄; keys(🗄️))
💻(📄, 🗄️[📄], 🎤);
}
var dotsgen = func() {

View File

@ -4,16 +4,16 @@ use std.io;
use std.unix;
var os_time = func() {
return "[\e[33;1m"~os.time()~"\e[0m] ";
return "\e[33;1m["~os.time()~"]\e[0m ";
}
var err_hd = func() {
return "[\e[91;1merror\e[0m] ";
return "\e[91;1m[error]\e[0m ";
}
var info_hd = func() {
return "[\e[96;1minfo\e[0m] ";
return "\e[96;1m[info]\e[0m ";
}
var modified_hd = func() {
return "[\e[92;1mmodified\e[0m] ";
return "\e[92;1m[modified]\e[0m ";
}
var usage = func() {
println(os_time(),info_hd(),"\e[1musage: nasal watchdog.nas <filename> [\"argv\"]\e[0m");
@ -41,7 +41,7 @@ if (size(argv)==2) {
var modified_time = io.fstat(filename).st_mtime;
println(os_time(),info_hd(),"\e[1mwatching ",filename," ..\e[0m");
while(1) {
unix.sleep(1);
unix.sleep(5);
if (!io.exists(filename)) {
println(os_time(),err_hd(),"\e[1mfile <",filename,"> does not exist\e[0m");
break;

116
test/wavecity.nas Normal file
View File

@ -0,0 +1,116 @@
use std.runtime;
runtime.windows.set_utf8_output();
var road_enum = {
null: 0,
narrow: 1,
wide: 2
};
var block = {
"┌": [road_enum.null, road_enum.narrow, road_enum.narrow, road_enum.null],
"└": [road_enum.narrow, road_enum.narrow, road_enum.null, road_enum.null],
"┐": [road_enum.null, road_enum.null, road_enum.narrow, road_enum.narrow],
"┘": [road_enum.narrow, road_enum.null, road_enum.null, road_enum.narrow],
"╪": [road_enum.narrow, road_enum.wide, road_enum.narrow, road_enum.wide],
"│": [road_enum.narrow, road_enum.null, road_enum.narrow, road_enum.null],
"─": [road_enum.null, road_enum.narrow, road_enum.null, road_enum.narrow],
"┼": [road_enum.narrow, road_enum.narrow, road_enum.narrow, road_enum.narrow],
"╫": [road_enum.wide, road_enum.narrow, road_enum.wide, road_enum.narrow],
"╬": [road_enum.wide, road_enum.wide, road_enum.wide, road_enum.wide],
"═": [road_enum.null, road_enum.wide, road_enum.null, road_enum.wide],
"║": [road_enum.wide, road_enum.null, road_enum.wide, road_enum.null],
# "╒": [road_enum.null, road_enum.wide, road_enum.narrow, road_enum.null],
# "╓": [road_enum.null, road_enum.narrow, road_enum.wide, road_enum.null],
"╔": [road_enum.null, road_enum.wide, road_enum.wide, road_enum.null],
# "╕": [road_enum.null, road_enum.null, road_enum.narrow, road_enum.wide],
# "╖": [road_enum.null, road_enum.null, road_enum.wide, road_enum.narrow],
"╗": [road_enum.null, road_enum.null, road_enum.wide, road_enum.wide],
# "╘": [road_enum.narrow, road_enum.wide, road_enum.null, road_enum.null],
# "╙": [road_enum.wide, road_enum.narrow, road_enum.null, road_enum.null],
"╚": [road_enum.wide, road_enum.wide, road_enum.null, road_enum.null],
# "╛": [road_enum.narrow, road_enum.null, road_enum.null, road_enum.wide],
# "╜": [road_enum.wide, road_enum.null, road_enum.null, road_enum.narrow],
"╝": [road_enum.wide, road_enum.null, road_enum.null, road_enum.wide],
"╞": [road_enum.narrow, road_enum.wide, road_enum.narrow, road_enum.null],
"╟": [road_enum.wide, road_enum.narrow, road_enum.wide, road_enum.null],
"╠": [road_enum.wide, road_enum.wide, road_enum.wide, road_enum.null],
"╡": [road_enum.narrow, road_enum.null, road_enum.narrow, road_enum.wide],
"╢": [road_enum.wide, road_enum.null, road_enum.wide, road_enum.narrow],
"╣": [road_enum.wide, road_enum.null, road_enum.wide, road_enum.wide],
"╤": [road_enum.null, road_enum.wide, road_enum.narrow, road_enum.wide],
"╥": [road_enum.null, road_enum.narrow, road_enum.wide, road_enum.narrow],
"╦": [road_enum.null, road_enum.wide, road_enum.wide, road_enum.wide],
"╧": [road_enum.narrow, road_enum.wide, road_enum.null, road_enum.wide],
"╨": [road_enum.wide, road_enum.narrow, road_enum.null, road_enum.narrow],
"╩": [road_enum.wide, road_enum.wide, road_enum.null, road_enum.wide],
" ": [road_enum.null, road_enum.null, road_enum.null, road_enum.null]
};
var choice = func(above_block_char,
left_block_char,
flag_no_road_at_right,
flag_no_road_at_bottom) {
var above_block = block[above_block_char];
var left_block = block[left_block_char];
var block_char_set = keys(block);
var possible = [];
foreach(var bcs; block_char_set) {
var this_block = block[bcs];
if (this_block[0] == above_block[2] and
this_block[3] == left_block[1]) {
if (flag_no_road_at_right and this_block[1]!=road_enum.null) {
continue;
}
if (flag_no_road_at_bottom and this_block[2]!=road_enum.null) {
continue;
}
append(possible, bcs);
}
}
if (!size(possible)) {
return " ";
}
func() {
if (vecindex(possible, " ")!=nil) {
for(var i = 0; i < 64; i+= 1) {
append(possible, " ");
}
}
}();
return possible[rand()*size(possible)];
}
var print_whole_line = func(this_line) {
var res = "";
foreach(var i; this_line) {
res ~= i;
}
println(res);
}
srand();
var last_line = [];
for(var i = 0; i<100; i+=1) {
append(last_line, " ");
}
for(var iteration_times = 0; iteration_times < 25; iteration_times += 1) {
var this_line = [];
var left_block = " ";
for(var i = 0; i < 100; i += 1) {
var this_block = choice(
last_line[i],
left_block,
i==99,
iteration_times==24
);
left_block = this_block;
append(this_line, this_block);
}
print_whole_line(this_line);
last_line = this_line;
}

View File

@ -1,6 +1,6 @@
# wave collapse function 2022/4/10
# by ValKmjolnir
use std.os;
use std.runtime;
srand();
var table=[
@ -96,8 +96,7 @@ var map = func() {
}();
# enable unicode
if (os.platform()=="windows")
system("chcp 65001");
runtime.windows.set_utf8_output();
map.new(90);
for(var iter=0;iter<40;iter+=1) {