Merge branch 'master' into master
This commit is contained in:
commit
0c54f216fc
|
@ -17,10 +17,8 @@ jobs:
|
||||||
git push -f origin next_macOS
|
git push -f origin next_macOS
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
cd module
|
make -j6
|
||||||
make all -j4
|
|
||||||
cd ..
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
- name: Package
|
- name: Package
|
||||||
|
@ -33,7 +31,7 @@ jobs:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
draft: false
|
draft: false
|
||||||
files: |
|
files: |
|
||||||
nasal-Darwin.tar
|
nasal-macOS-aarch64.tar
|
||||||
|
|
||||||
linux-x86_64-build:
|
linux-x86_64-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -46,10 +44,8 @@ jobs:
|
||||||
git push -f origin next_linux_x86_64
|
git push -f origin next_linux_x86_64
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
cd module
|
make -j6
|
||||||
make all -j4
|
|
||||||
cd ..
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
- name: Package
|
- name: Package
|
||||||
|
@ -62,4 +58,4 @@ jobs:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
draft: false
|
draft: false
|
||||||
files: |
|
files: |
|
||||||
nasal-Linux.tar
|
nasal-linux-x86_64.tar
|
||||||
|
|
|
@ -14,10 +14,8 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
cd module
|
make -j6
|
||||||
make all -j4
|
|
||||||
cd ..
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
|
@ -27,9 +25,7 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
cd module
|
make -j6
|
||||||
make all -j4
|
|
||||||
cd ..
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: make test
|
run: make test
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
build/
|
build/
|
||||||
out/
|
out/
|
||||||
dist/
|
dist/
|
||||||
cmake-build-*/
|
cmake-build-*
|
||||||
|
cmake-windows-*
|
||||||
|
|
||||||
# IDE and editor files
|
# IDE and editor files
|
||||||
.vscode/
|
.vscode/
|
||||||
|
@ -49,7 +50,9 @@ cmake-build-*/
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
nasal
|
nasal
|
||||||
|
nasal-format
|
||||||
nasal.exe
|
nasal.exe
|
||||||
|
nasal-format.exe
|
||||||
|
|
||||||
# Visual Studio specific
|
# Visual Studio specific
|
||||||
*.sln
|
*.sln
|
||||||
|
|
|
@ -9,9 +9,13 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall")
|
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall")
|
||||||
|
|
||||||
add_compile_options(-fPIC)
|
# MSVC does not need -fPIC
|
||||||
|
if (NOT MSVC)
|
||||||
|
add_compile_options(-fPIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
# MSVC needs this command option to really enable utf-8 output
|
# MSVC needs this command option to really enable utf-8 output
|
||||||
if(MSVC)
|
if (MSVC)
|
||||||
add_compile_options(/utf-8)
|
add_compile_options(/utf-8)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -19,9 +23,6 @@ if (APPLE)
|
||||||
add_compile_options(-mmacosx-version-min=10.15)
|
add_compile_options(-mmacosx-version-min=10.15)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# generate release executables
|
|
||||||
set(CMAKE_BUILD_TYPE "Release")
|
|
||||||
|
|
||||||
# build nasal used object
|
# build nasal used object
|
||||||
set(NASAL_OBJECT_SOURCE_FILE
|
set(NASAL_OBJECT_SOURCE_FILE
|
||||||
${CMAKE_SOURCE_DIR}/src/cli/cli.cpp
|
${CMAKE_SOURCE_DIR}/src/cli/cli.cpp
|
||||||
|
@ -40,6 +41,7 @@ set(NASAL_OBJECT_SOURCE_FILE
|
||||||
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
${CMAKE_SOURCE_DIR}/src/util/util.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
|
${CMAKE_SOURCE_DIR}/src/ast_dumper.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/ast_format.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
|
${CMAKE_SOURCE_DIR}/src/ast_visitor.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_ast.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
||||||
|
@ -61,12 +63,18 @@ target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
|
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
|
||||||
target_link_libraries(nasal nasal-object)
|
target_link_libraries(nasal nasal-object)
|
||||||
|
|
||||||
|
# build nasal-format
|
||||||
|
add_executable(nasal-format ${CMAKE_SOURCE_DIR}/src/format.cpp)
|
||||||
|
target_link_libraries(nasal-format nasal-object)
|
||||||
|
|
||||||
# link ldl and lpthread
|
# link ldl and lpthread
|
||||||
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
target_link_libraries(nasal dl)
|
target_link_libraries(nasal dl)
|
||||||
target_link_libraries(nasal pthread)
|
target_link_libraries(nasal pthread)
|
||||||
|
target_link_libraries(nasal-format pthread)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
target_include_directories(nasal-format PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
# copy nasal from build dir to the outside dir
|
# copy nasal from build dir to the outside dir
|
||||||
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
|
@ -76,6 +84,12 @@ if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
|
||||||
${CMAKE_SOURCE_DIR}/build/nasal
|
${CMAKE_SOURCE_DIR}/build/nasal
|
||||||
${CMAKE_SOURCE_DIR}/nasal
|
${CMAKE_SOURCE_DIR}/nasal
|
||||||
)
|
)
|
||||||
|
add_custom_command(
|
||||||
|
TARGET nasal-format POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
${CMAKE_SOURCE_DIR}/build/nasal-format
|
||||||
|
${CMAKE_SOURCE_DIR}/nasal-format
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# build module
|
# build module
|
||||||
|
@ -103,16 +117,21 @@ target_link_libraries(mat module-used-object)
|
||||||
|
|
||||||
add_library(nasock SHARED ${CMAKE_SOURCE_DIR}/module/nasocket.cpp)
|
add_library(nasock SHARED ${CMAKE_SOURCE_DIR}/module/nasocket.cpp)
|
||||||
target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
target_include_directories(nasock PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(nasock ws2_32)
|
||||||
|
endif()
|
||||||
target_link_libraries(nasock module-used-object)
|
target_link_libraries(nasock module-used-object)
|
||||||
|
|
||||||
# Add web library
|
# Add web library, not for MSVC now
|
||||||
add_library(nasal-web SHARED
|
if (NOT MSVC)
|
||||||
src/nasal_web.cpp
|
add_library(nasal-web SHARED
|
||||||
${NASAL_OBJECT_SOURCE_FILE}
|
src/nasal_web.cpp
|
||||||
)
|
${NASAL_OBJECT_SOURCE_FILE}
|
||||||
target_include_directories(nasal-web PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
)
|
||||||
set_target_properties(nasal-web PROPERTIES
|
target_include_directories(nasal-web PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
C_VISIBILITY_PRESET hidden
|
set_target_properties(nasal-web PROPERTIES
|
||||||
CXX_VISIBILITY_PRESET hidden
|
C_VISIBILITY_PRESET hidden
|
||||||
VISIBILITY_INLINES_HIDDEN ON
|
CXX_VISIBILITY_PRESET hidden
|
||||||
)
|
VISIBILITY_INLINES_HIDDEN ON
|
||||||
|
)
|
||||||
|
endif()
|
|
@ -88,7 +88,7 @@ Make sure thread model is `posix thread model`, otherwise no thread library exis
|
||||||
|
|
||||||
### __Windows (Visual Studio)__
|
### __Windows (Visual Studio)__
|
||||||
|
|
||||||
There is a [__CMakelists.txt__](./CMakeLists.txt) to create project.
|
There is a [__CMakelists.txt__](./CMakeLists.txt) to create project. Recently we find how to build it with command line tools: [__Build Nasal-Interpreter on Windows__](./doc/windows-build.md).
|
||||||
|
|
||||||
### __Linux / macOS / Unix__
|
### __Linux / macOS / Unix__
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ Windows 平台的预览版解释器现在还没配置相关流水线,
|
||||||
### __Windows 平台 (Vistual Studio)__
|
### __Windows 平台 (Vistual Studio)__
|
||||||
|
|
||||||
项目提供了 [__CMakeLists.txt__](../CMakeLists.txt) 用于在`Visual Studio`中创建项目。
|
项目提供了 [__CMakeLists.txt__](../CMakeLists.txt) 用于在`Visual Studio`中创建项目。
|
||||||
|
最近我们总结了命令行编译的方法 [__如何在 Windows 平台编译 Nasal-Interpreter__](./windows-build.md)。
|
||||||
|
|
||||||
### __Linux / macOS / Unix 平台__
|
### __Linux / macOS / Unix 平台__
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Build Nasal-Interpreter on Windows
|
||||||
|
|
||||||
|
## MSVC / Visual Studio
|
||||||
|
|
||||||
|
Need CMake and Visual Studio 2022. Remember to add MSBuild.exe to Path.
|
||||||
|
|
||||||
|
Valid on powershell:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir cmake-windows-msvc
|
||||||
|
cd cmake-windows-msvc
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022"
|
||||||
|
MSBuild.exe nasal.sln /p:Configuration=Release /p:Platform=x64
|
||||||
|
```
|
||||||
|
|
||||||
|
## MingW-W64
|
||||||
|
|
||||||
|
Need CMake and MingW-W64. Remember to add MingW-W64 bin to Path.
|
||||||
|
|
||||||
|
Valid on powershell:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir cmake-windows-mingw
|
||||||
|
cd cmake-windows-mingw
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
|
||||||
|
mingw32-make.exe -j6
|
||||||
|
```
|
10
makefile
10
makefile
|
@ -333,10 +333,10 @@ test:
|
||||||
@ ./nasal -t -d test/regex_test.nas
|
@ ./nasal -t -d test/regex_test.nas
|
||||||
@ ./nasal -t -d test/replace_test.nas
|
@ ./nasal -t -d test/replace_test.nas
|
||||||
@ ./nasal -e test/scalar.nas hello world
|
@ ./nasal -e test/scalar.nas hello world
|
||||||
@ ./nasal test/subprocess_test.nas
|
@ ./nasal -t test/subprocess_test.nas
|
||||||
@ ./nasal -e test/trait.nas
|
@ ./nasal -t test/trait.nas
|
||||||
@ ./nasal -t -d test/turingmachine.nas
|
@ ./nasal -t -d test/turingmachine.nas
|
||||||
@ ./nasal -d test/wavecollapse.nas
|
@ ./nasal -t -d test/wavecollapse.nas
|
||||||
@ ./nasal -d test/wavecity.nas
|
@ ./nasal -t -d test/wavecity.nas
|
||||||
@ ./nasal test/word_collector.nas test/md5compare.nas
|
@ ./nasal -t test/word_collector.nas test/md5compare.nas
|
||||||
@ ./nasal -t -d test/ycombinator.nas
|
@ ./nasal -t -d test/ycombinator.nas
|
||||||
|
|
|
@ -12,9 +12,9 @@ ifndef OS
|
||||||
OS = $(shell uname)
|
OS = $(shell uname)
|
||||||
endif
|
endif
|
||||||
ifeq ($(OS), Darwin)
|
ifeq ($(OS), Darwin)
|
||||||
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15
|
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -mmacosx-version-min=10.15 -I ../src
|
||||||
else
|
else
|
||||||
CXXFLAGS = -std=$(STD) -c -O3 -fPIC
|
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I ../src
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: $(dynamic_libs_so)
|
all: $(dynamic_libs_so)
|
||||||
|
@ -29,7 +29,7 @@ libfib.so: fib.cpp $(used_header) $(used_object)
|
||||||
@ rm fib.o
|
@ rm fib.o
|
||||||
libfib.dll: fib.cpp $(used_header) $(used_object)
|
libfib.dll: fib.cpp $(used_header) $(used_object)
|
||||||
@ echo [Compiling] libfib.dll
|
@ echo [Compiling] libfib.dll
|
||||||
@ $(CXX) -std=$(STD) -c -O3 fib.cpp -fPIC -o fib.o
|
@ $(CXX) -std=$(STD) -c -O3 fib.cpp -fPIC -o fib.o -I ../src
|
||||||
@ $(CXX) -shared -o libfib.dll fib.o $(used_object) -static
|
@ $(CXX) -shared -o libfib.dll fib.o $(used_object) -static
|
||||||
@ del fib.o
|
@ del fib.o
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ libkey.so: keyboard.cpp $(used_header) $(used_object)
|
||||||
@ rm keyboard.o
|
@ rm keyboard.o
|
||||||
libkey.dll: keyboard.cpp $(used_header) $(used_object)
|
libkey.dll: keyboard.cpp $(used_header) $(used_object)
|
||||||
@ echo [Compiling] libkey.dll
|
@ echo [Compiling] libkey.dll
|
||||||
@ $(CXX) -std=$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static
|
@ $(CXX) -std=$(STD) -c -O3 keyboard.cpp -fPIC -o keyboard.o -static -I ../src
|
||||||
@ $(CXX) -shared -o libkey.dll keyboard.o $(used_object) -static
|
@ $(CXX) -shared -o libkey.dll keyboard.o $(used_object) -static
|
||||||
@ del keyboard.o
|
@ del keyboard.o
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ libnasock.so: nasocket.cpp $(used_header) $(used_object)
|
||||||
@ rm nasocket.o
|
@ rm nasocket.o
|
||||||
libnasock.dll: nasocket.cpp $(used_header) $(used_object)
|
libnasock.dll: nasocket.cpp $(used_header) $(used_object)
|
||||||
@ echo [Compiling] libnasock.dll
|
@ echo [Compiling] libnasock.dll
|
||||||
@ $(CXX) -std=$(STD) -c -O3 nasocket.cpp -fPIC -o nasocket.o -lwsock32 -static
|
@ $(CXX) -std=$(STD) -c -O3 nasocket.cpp -fPIC -I ../src -o nasocket.o -lwsock32 -static
|
||||||
@ $(CXX) -shared -o libnasock.dll nasocket.o $(used_object) -lwsock32 -static
|
@ $(CXX) -shared -o libnasock.dll nasocket.o $(used_object) -lwsock32 -static
|
||||||
@ del nasocket.o
|
@ del nasocket.o
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ libmat.so: matrix.cpp $(used_header) $(used_object)
|
||||||
@ rm matrix.o
|
@ rm matrix.o
|
||||||
libmat.dll: matrix.cpp $(used_header) $(used_object)
|
libmat.dll: matrix.cpp $(used_header) $(used_object)
|
||||||
@ echo [Compiling] libmat.dll
|
@ echo [Compiling] libmat.dll
|
||||||
@ $(CXX) -std=$(STD) -c -O3 matrix.cpp -fPIC -o matrix.o -static
|
@ $(CXX) -std=$(STD) -c -O3 matrix.cpp -fPIC -I ../src -o matrix.o -static
|
||||||
@ $(CXX) -shared -o libmat.dll matrix.o $(used_object) -static
|
@ $(CXX) -shared -o libmat.dll matrix.o $(used_object) -static
|
||||||
@ del matrix.o
|
@ del matrix.o
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ private:
|
||||||
if (indent.size() && indent.back()=="│ ") {
|
if (indent.size() && indent.back()=="│ ") {
|
||||||
indent.back() = "├──";
|
indent.back() = "├──";
|
||||||
}
|
}
|
||||||
for(const auto& i : indent) {
|
for (const auto& i : indent) {
|
||||||
std::cout << i;
|
std::cout << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,427 @@
|
||||||
|
#include "ast_format.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
bool ast_format::visit_use_stmt(use_stmt* node) {
|
||||||
|
dump_formating_node_info(node, "use statement");
|
||||||
|
out << "use ";
|
||||||
|
for(auto i : node->get_path()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_path().back()) {
|
||||||
|
out << ".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_null_expr(null_expr* node) {
|
||||||
|
dump_formating_node_info(node, "null expression");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_nil_expr(nil_expr* node) {
|
||||||
|
dump_formating_node_info(node, "nil expression");
|
||||||
|
out << "nil";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_number_literal(number_literal* node) {
|
||||||
|
dump_formating_node_info(node, "number expression");
|
||||||
|
out << node->get_raw_text();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_string_literal(string_literal* node) {
|
||||||
|
dump_formating_node_info(node, "string expression");
|
||||||
|
out << "\"" << util::rawstr(node->get_content()) << "\"";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_identifier(identifier* node) {
|
||||||
|
dump_formating_node_info(node, "identifier");
|
||||||
|
out << node->get_name();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_bool_literal(bool_literal* node) {
|
||||||
|
dump_formating_node_info(node, "bool expression");
|
||||||
|
out << (node->get_flag()? "true" : "false");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_vector_expr(vector_expr* node) {
|
||||||
|
dump_formating_node_info(node, "vector expression");
|
||||||
|
out << "[";
|
||||||
|
for(auto i : node->get_elements()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_elements().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_hash_expr(hash_expr* node) {
|
||||||
|
dump_formating_node_info(node, "hash expression");
|
||||||
|
out << "{";
|
||||||
|
for(auto i : node->get_members()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_members().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_hash_pair(hash_pair* node) {
|
||||||
|
dump_formating_node_info(node, "hash pair");
|
||||||
|
bool contain_not_identifier = false;
|
||||||
|
for (auto c : node->get_name()) {
|
||||||
|
if (!(std::isdigit(c) || std::isalpha(c) || c == '_')) {
|
||||||
|
contain_not_identifier = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (contain_not_identifier) {
|
||||||
|
out << "\"" << node->get_name() << "\"";
|
||||||
|
} else {
|
||||||
|
out << node->get_name();
|
||||||
|
}
|
||||||
|
if (node->get_value()) {
|
||||||
|
out << " : ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_function(function* node) {
|
||||||
|
dump_formating_node_info(node, "function");
|
||||||
|
out << "func(";
|
||||||
|
for(auto i : node->get_parameter_list()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_parameter_list().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ") ";
|
||||||
|
if (node->get_code_block()->get_expressions().empty()) {
|
||||||
|
out << "{}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_code_block(code_block* node) {
|
||||||
|
dump_formating_node_info(node, "code block");
|
||||||
|
out << "{\n";
|
||||||
|
push_indent();
|
||||||
|
for(auto i : node->get_expressions()) {
|
||||||
|
dump_indent();
|
||||||
|
i->accept(this);
|
||||||
|
if (need_dump_semi(i)) {
|
||||||
|
out << ";\n";
|
||||||
|
} else {
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pop_indent();
|
||||||
|
dump_indent();
|
||||||
|
out << "}";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_parameter(parameter* node) {
|
||||||
|
dump_formating_node_info(node, "parameter");
|
||||||
|
out << node->get_parameter_name();
|
||||||
|
switch (node->get_parameter_type()) {
|
||||||
|
case parameter::kind::normal_parameter: break;
|
||||||
|
case parameter::kind::dynamic_parameter: out << "..."; break;
|
||||||
|
case parameter::kind::default_parameter: out << " = "; break;
|
||||||
|
}
|
||||||
|
if (node->get_default_value()) {
|
||||||
|
node->get_default_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_ternary_operator(ternary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "ternary operator");
|
||||||
|
out << "(";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << " ? ";
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
out << " : ";
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_binary_operator(binary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "binary operator");
|
||||||
|
out << "(";
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
switch(node->get_operator_type()) {
|
||||||
|
case binary_operator::kind::add: out << " + "; break;
|
||||||
|
case binary_operator::kind::sub: out << " - "; break;
|
||||||
|
case binary_operator::kind::mult: out << " * "; break;
|
||||||
|
case binary_operator::kind::div: out << " / "; break;
|
||||||
|
case binary_operator::kind::concat: out << " ~ "; break;
|
||||||
|
case binary_operator::kind::bitwise_and: out << " & "; break;
|
||||||
|
case binary_operator::kind::bitwise_or: out << " | "; break;
|
||||||
|
case binary_operator::kind::bitwise_xor: out << " ^ "; break;
|
||||||
|
case binary_operator::kind::cmpeq: out << " == "; break;
|
||||||
|
case binary_operator::kind::cmpneq: out << " != "; break;
|
||||||
|
case binary_operator::kind::grt: out << " > "; break;
|
||||||
|
case binary_operator::kind::geq: out << " >= "; break;
|
||||||
|
case binary_operator::kind::less: out << " < "; break;
|
||||||
|
case binary_operator::kind::leq: out << " <= "; break;
|
||||||
|
case binary_operator::kind::condition_and: out << " and "; break;
|
||||||
|
case binary_operator::kind::condition_or: out << " or "; break;
|
||||||
|
case binary_operator::kind::null_chain: out << " ?? "; break;
|
||||||
|
}
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_unary_operator(unary_operator* node) {
|
||||||
|
dump_formating_node_info(node, "unary operator");
|
||||||
|
switch(node->get_operator_type()) {
|
||||||
|
case unary_operator::kind::negative: out << "-"; break;
|
||||||
|
case unary_operator::kind::logical_not: out << "!"; break;
|
||||||
|
case unary_operator::kind::bitwise_not: out << "~"; break;
|
||||||
|
}
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_expr(call_expr* node) {
|
||||||
|
dump_formating_node_info(node, "call expression");
|
||||||
|
node->get_first()->accept(this);
|
||||||
|
for(auto i : node->get_calls()) {
|
||||||
|
i->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_hash(call_hash* node) {
|
||||||
|
dump_formating_node_info(node, "call hash");
|
||||||
|
out << "." << node->get_field();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_null_access(null_access* node) {
|
||||||
|
dump_formating_node_info(node, "null access operator(?.)");
|
||||||
|
out << "?." << node->get_field();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_vector(call_vector* node) {
|
||||||
|
dump_formating_node_info(node, "call vector");
|
||||||
|
out << "[";
|
||||||
|
for(auto i : node->get_slices()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_slices().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << "]";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_call_function(call_function* node) {
|
||||||
|
dump_formating_node_info(node, "call function");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_argument()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_argument().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_slice_vector(slice_vector* node) {
|
||||||
|
dump_formating_node_info(node, "slice vector");
|
||||||
|
node->get_begin()->accept(this);
|
||||||
|
if (node->get_end()) {
|
||||||
|
out << " : ";
|
||||||
|
node->get_end()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_definition_expr(definition_expr* node) {
|
||||||
|
dump_formating_node_info(node, "definition");
|
||||||
|
out << "var ";
|
||||||
|
if (node->get_variable_name()) {
|
||||||
|
node->get_variable_name()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_variables()->accept(this);
|
||||||
|
}
|
||||||
|
out << " = ";
|
||||||
|
if (node->get_tuple()) {
|
||||||
|
node->get_tuple()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_assignment_expr(assignment_expr* node) {
|
||||||
|
dump_formating_node_info(node, "assignment");
|
||||||
|
node->get_left()->accept(this);
|
||||||
|
switch(node->get_assignment_type()) {
|
||||||
|
case assignment_expr::kind::add_equal: out << " += "; break;
|
||||||
|
case assignment_expr::kind::sub_equal: out << " -= "; break;
|
||||||
|
case assignment_expr::kind::mult_equal: out << " *= "; break;
|
||||||
|
case assignment_expr::kind::div_equal: out << " /= "; break;
|
||||||
|
case assignment_expr::kind::concat_equal: out << " ~= "; break;
|
||||||
|
case assignment_expr::kind::equal: out << " = "; break;
|
||||||
|
case assignment_expr::kind::bitwise_and_equal: out << " &= "; break;
|
||||||
|
case assignment_expr::kind::bitwise_or_equal: out << " |= "; break;
|
||||||
|
case assignment_expr::kind::bitwise_xor_equal: out << " ^= "; break;
|
||||||
|
}
|
||||||
|
node->get_right()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_multi_identifier(multi_identifier* node) {
|
||||||
|
dump_formating_node_info(node, "multi identifier");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_variables()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_variables().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_tuple_expr(tuple_expr* node) {
|
||||||
|
dump_formating_node_info(node, "tuple expression");
|
||||||
|
out << "(";
|
||||||
|
for(auto i : node->get_elements()) {
|
||||||
|
i->accept(this);
|
||||||
|
if (i != node->get_elements().back()) {
|
||||||
|
out << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << ")";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_multi_assign(multi_assign* node) {
|
||||||
|
dump_formating_node_info(node, "multi assign");
|
||||||
|
node->get_tuple()->accept(this);
|
||||||
|
out << " = ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_while_expr(while_expr* node) {
|
||||||
|
dump_formating_node_info(node, "while statement");
|
||||||
|
out << "while (";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_for_expr(for_expr* node) {
|
||||||
|
dump_formating_node_info(node, "for statement");
|
||||||
|
out << "for (";
|
||||||
|
node->get_initial()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_step()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_iter_expr(iter_expr* node) {
|
||||||
|
dump_formating_node_info(node, "iteration expression");
|
||||||
|
if (node->is_definition()) {
|
||||||
|
out << "var ";
|
||||||
|
}
|
||||||
|
if (node->get_name()) {
|
||||||
|
node->get_name()->accept(this);
|
||||||
|
} else {
|
||||||
|
node->get_call()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_forei_expr(forei_expr* node) {
|
||||||
|
dump_formating_node_info(node, "forindex/foreach statement");
|
||||||
|
if (node->get_loop_type()==forei_expr::kind::foreach) {
|
||||||
|
out << "foreach ";
|
||||||
|
} else {
|
||||||
|
out << "forindex ";
|
||||||
|
}
|
||||||
|
out << "(";
|
||||||
|
node->get_iterator()->accept(this);
|
||||||
|
out << "; ";
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_condition_expr(condition_expr* node) {
|
||||||
|
dump_formating_node_info(node, "condition statement");
|
||||||
|
out << "if ";
|
||||||
|
node->get_if_statement()->accept(this);
|
||||||
|
for (auto i : node->get_elsif_stataments()) {
|
||||||
|
out << " elsif ";
|
||||||
|
i->accept(this);
|
||||||
|
}
|
||||||
|
if (node->get_else_statement()) {
|
||||||
|
out << " else ";
|
||||||
|
node->get_else_statement()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_if_expr(if_expr* node) {
|
||||||
|
dump_formating_node_info(node, "if statement");
|
||||||
|
if (node->get_condition()) {
|
||||||
|
out << "(";
|
||||||
|
node->get_condition()->accept(this);
|
||||||
|
out << ") ";
|
||||||
|
}
|
||||||
|
node->get_code_block()->accept(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_continue_expr(continue_expr* node) {
|
||||||
|
dump_formating_node_info(node, "continue statement");
|
||||||
|
out << "continue";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_break_expr(break_expr* node) {
|
||||||
|
dump_formating_node_info(node, "break statement");
|
||||||
|
out << "break";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ast_format::visit_return_expr(return_expr* node) {
|
||||||
|
dump_formating_node_info(node, "return statement");
|
||||||
|
out << "return ";
|
||||||
|
if (node->get_value()) {
|
||||||
|
node->get_value()->accept(this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ast_visitor.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace nasal {
|
||||||
|
|
||||||
|
class ast_format: public ast_visitor {
|
||||||
|
private:
|
||||||
|
std::ofstream out;
|
||||||
|
std::vector<std::string> indent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void push_indent() {
|
||||||
|
indent.push_back(" ");
|
||||||
|
}
|
||||||
|
void pop_indent() {
|
||||||
|
if (indent.size()) {
|
||||||
|
indent.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump_indent() {
|
||||||
|
for (const auto& i : indent) {
|
||||||
|
out << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump_formating_node_info(expr* n, const char* name) {
|
||||||
|
std::cout << " formating " << name << " @ 0x";
|
||||||
|
std::cout << std::hex << n << std::dec << "\n";
|
||||||
|
}
|
||||||
|
bool need_dump_semi(expr* n) {
|
||||||
|
switch (n->get_type()) {
|
||||||
|
case expr_type::ast_use:
|
||||||
|
case expr_type::ast_null:
|
||||||
|
case expr_type::ast_nil:
|
||||||
|
case expr_type::ast_num:
|
||||||
|
case expr_type::ast_str:
|
||||||
|
case expr_type::ast_bool:
|
||||||
|
case expr_type::ast_vec:
|
||||||
|
case expr_type::ast_hash:
|
||||||
|
case expr_type::ast_call:
|
||||||
|
case expr_type::ast_multi_assign:
|
||||||
|
case expr_type::ast_unary:
|
||||||
|
case expr_type::ast_binary:
|
||||||
|
case expr_type::ast_ternary: return true;
|
||||||
|
case expr_type::ast_def: {
|
||||||
|
auto dn = reinterpret_cast<definition_expr*>(n);
|
||||||
|
if (dn->get_value() &&
|
||||||
|
dn->get_value()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case expr_type::ast_assign: {
|
||||||
|
auto dn = reinterpret_cast<assignment_expr*>(n);
|
||||||
|
if (dn->get_right() &&
|
||||||
|
dn->get_right()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case expr_type::ast_ret: {
|
||||||
|
auto dn = reinterpret_cast<return_expr*>(n);
|
||||||
|
if (dn->get_value() &&
|
||||||
|
dn->get_value()->get_type() == expr_type::ast_func) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_null_access(null_access*) 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:
|
||||||
|
ast_format(const std::string output_file): out(output_file) {
|
||||||
|
if (out.fail()) {
|
||||||
|
throw std::runtime_error("can't open file: " + output_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_format(code_block* root) {
|
||||||
|
std::cout << "nasal-format is not stable right now, ";
|
||||||
|
std::cout << "take care of source code!\n";
|
||||||
|
dump_formating_node_info(root, "program root");
|
||||||
|
bool is_use_statement = true;
|
||||||
|
for (auto i : root->get_expressions()) {
|
||||||
|
if (is_use_statement && i->get_type() != expr_type::ast_use) {
|
||||||
|
is_use_statement = false;
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
i->accept(this);
|
||||||
|
if (need_dump_semi(i)) {
|
||||||
|
out << ";\n";
|
||||||
|
} else {
|
||||||
|
out << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,12 @@
|
||||||
|
#include "nasal.h"
|
||||||
#include "cli/cli.h"
|
#include "cli/cli.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "nasal_parse.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
namespace nasal::cli {
|
namespace nasal::cli {
|
||||||
|
|
||||||
|
@ -59,4 +65,75 @@ std::ostream& help(std::ostream& out) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& nasal_format_help(std::ostream& out) {
|
||||||
|
out
|
||||||
|
<< "\n"
|
||||||
|
<< " ,--#-,\n"
|
||||||
|
<< "<3 / \\____\\ <3\n"
|
||||||
|
<< " |_|__A_|\n"
|
||||||
|
<< "\nnasal-format <option>\n"
|
||||||
|
<< "option:\n"
|
||||||
|
<< " -h, --help | get help.\n"
|
||||||
|
<< " -v, --version | get version.\n"
|
||||||
|
<< "\nnasal-format <file>\n"
|
||||||
|
<< "file:\n"
|
||||||
|
<< " <filename> | file to be formatted.\n"
|
||||||
|
<< "\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& logo(std::ostream& out) {
|
||||||
|
out
|
||||||
|
<< "\n"
|
||||||
|
<< " __ _\n"
|
||||||
|
<< " /\\ \\ \\__ _ ___ __ _| |\n"
|
||||||
|
<< " / \\/ / _` / __|/ _` | |\n"
|
||||||
|
<< " / /\\ / (_| \\__ \\ (_| | |\n"
|
||||||
|
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "ver : " << __nasver__
|
||||||
|
<< " " << nasal::util::get_platform()
|
||||||
|
<< " " << nasal::util::get_arch()
|
||||||
|
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
|
||||||
|
<< "std : c++ " << __cplusplus << "\n"
|
||||||
|
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
|
||||||
|
<< "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
||||||
|
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
||||||
|
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "presented by fgprc members:\n"
|
||||||
|
<< " - http://fgprc.org\n"
|
||||||
|
<< " - http://fgprc.org.cn\n"
|
||||||
|
<< "\n"
|
||||||
|
<< "input <nasal-format -h> to get help.\n\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& version(std::ostream& out) {
|
||||||
|
std::srand(static_cast<u32>(std::time(nullptr)));
|
||||||
|
|
||||||
|
f64 num = 0;
|
||||||
|
for(u32 i = 0; i<5; ++i) {
|
||||||
|
num = (num+rand())*(1.0/(RAND_MAX+1.0));
|
||||||
|
}
|
||||||
|
// give you 5% to see this easter egg
|
||||||
|
if (num<0.05) {
|
||||||
|
nasal::parse::easter_egg();
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "nasal version " << __nasver__;
|
||||||
|
out << " " << nasal::util::get_platform();
|
||||||
|
out << " " << nasal::util::get_arch();
|
||||||
|
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& nasal_format_version(std::ostream& out) {
|
||||||
|
out << "nasal-format version " << __nasver__ << "-beta";
|
||||||
|
out << " " << nasal::util::get_platform();
|
||||||
|
out << " " << nasal::util::get_arch();
|
||||||
|
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -69,5 +69,10 @@ const std::unordered_map<std::string, option> cli_options = {
|
||||||
cli_config parse(const std::vector<std::string>&);
|
cli_config parse(const std::vector<std::string>&);
|
||||||
|
|
||||||
std::ostream& help(std::ostream&);
|
std::ostream& help(std::ostream&);
|
||||||
|
std::ostream& nasal_format_help(std::ostream&);
|
||||||
|
|
||||||
|
std::ostream& logo(std::ostream&);
|
||||||
|
std::ostream& version(std::ostream&);
|
||||||
|
std::ostream& nasal_format_version(std::ostream&);
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include "nasal.h"
|
||||||
|
#include "nasal_lexer.h"
|
||||||
|
#include "nasal_ast.h"
|
||||||
|
#include "nasal_parse.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
#include "cli/cli.h"
|
||||||
|
#include "ast_format.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
|
void err() {
|
||||||
|
std::cerr << "invalid argument(s), use <nasal-format -h> to get help.\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(const nasal::cli::cli_config& config) {
|
||||||
|
nasal::lexer lex;
|
||||||
|
nasal::parse parse;
|
||||||
|
|
||||||
|
// lexer scans file to get tokens
|
||||||
|
lex.scan(config.input_file_path).chkerr();
|
||||||
|
|
||||||
|
// parser gets lexer's token list to compile
|
||||||
|
parse.compile(lex).chkerr();
|
||||||
|
|
||||||
|
nasal::ast_format("nasal-format-out.nas").do_format(parse.tree());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(i32 argc, const char* argv[]) {
|
||||||
|
// output version info
|
||||||
|
if (argc <= 1) {
|
||||||
|
err();
|
||||||
|
} else if (argc > 2) {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (config.has(nasal::cli::option::cli_help)) {
|
||||||
|
std::clog << nasal::cli::nasal_format_help;
|
||||||
|
} else if (config.has(nasal::cli::option::cli_version)) {
|
||||||
|
std::clog << nasal::cli::nasal_format_version;
|
||||||
|
} else if (config.input_file_path.size()) {
|
||||||
|
execute(config);
|
||||||
|
} else {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
64
src/main.cpp
64
src/main.cpp
|
@ -18,55 +18,8 @@
|
||||||
#include "repl/repl.h"
|
#include "repl/repl.h"
|
||||||
#include "cli/cli.h"
|
#include "cli/cli.h"
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
std::ostream& logo(std::ostream& out) {
|
|
||||||
out
|
|
||||||
<< "\n"
|
|
||||||
<< " __ _\n"
|
|
||||||
<< " /\\ \\ \\__ _ ___ __ _| |\n"
|
|
||||||
<< " / \\/ / _` / __|/ _` | |\n"
|
|
||||||
<< " / /\\ / (_| \\__ \\ (_| | |\n"
|
|
||||||
<< " \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
|
|
||||||
<< "\n"
|
|
||||||
<< "ver : " << __nasver__
|
|
||||||
<< " " << nasal::util::get_platform()
|
|
||||||
<< " " << nasal::util::get_arch()
|
|
||||||
<< " (" << __DATE__ << " " << __TIME__ << ")\n"
|
|
||||||
<< "std : c++ " << __cplusplus << "\n"
|
|
||||||
<< "core : " << std::thread::hardware_concurrency() << " core(s)\n"
|
|
||||||
<< "repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
|
|
||||||
<< "repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
|
|
||||||
<< "wiki : https://wiki.flightgear.org/Nasal_scripting_language\n"
|
|
||||||
<< "\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;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& version(std::ostream& out) {
|
|
||||||
std::srand(static_cast<u32>(std::time(nullptr)));
|
|
||||||
|
|
||||||
f64 num = 0;
|
|
||||||
for(u32 i = 0; i<5; ++i) {
|
|
||||||
num = (num+rand())*(1.0/(RAND_MAX+1.0));
|
|
||||||
}
|
|
||||||
// give you 5% to see this easter egg
|
|
||||||
if (num<0.05) {
|
|
||||||
nasal::parse::easter_egg();
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "nasal version " << __nasver__;
|
|
||||||
out << " " << nasal::util::get_platform();
|
|
||||||
out << " " << nasal::util::get_arch();
|
|
||||||
out << " (" << __DATE__ << " " << __TIME__ << ")\n";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
void err() {
|
void err() {
|
||||||
std::cerr << "invalid argument(s), use <nasal -h> to get help.\n";
|
std::cerr << "invalid argument(s), use <nasal -h> to get help.\n";
|
||||||
|
@ -121,6 +74,7 @@ void execute(const nasal::cli::cli_config& config) {
|
||||||
|
|
||||||
// run
|
// run
|
||||||
const auto start = clk::now();
|
const auto start = clk::now();
|
||||||
|
double gc_time_ms = 0.0;
|
||||||
if (config.has(option::cli_debug_mode)) {
|
if (config.has(option::cli_debug_mode)) {
|
||||||
auto debugger = std::make_unique<nasal::dbg>();
|
auto debugger = std::make_unique<nasal::dbg>();
|
||||||
debugger->run(
|
debugger->run(
|
||||||
|
@ -130,6 +84,7 @@ void execute(const nasal::cli::cli_config& config) {
|
||||||
config.has(option::cli_profile),
|
config.has(option::cli_profile),
|
||||||
config.has(option::cli_profile_all)
|
config.has(option::cli_profile_all)
|
||||||
);
|
);
|
||||||
|
gc_time_ms = debugger->get_gc_time_ms();
|
||||||
} else if (config.has(option::cli_show_execute_time) ||
|
} else if (config.has(option::cli_show_execute_time) ||
|
||||||
config.has(option::cli_detail_info) ||
|
config.has(option::cli_detail_info) ||
|
||||||
config.has(option::cli_limit_mode) ||
|
config.has(option::cli_limit_mode) ||
|
||||||
|
@ -138,20 +93,25 @@ void execute(const nasal::cli::cli_config& config) {
|
||||||
runtime->set_detail_report_info(config.has(option::cli_detail_info));
|
runtime->set_detail_report_info(config.has(option::cli_detail_info));
|
||||||
runtime->set_limit_mode_flag(config.has(option::cli_limit_mode));
|
runtime->set_limit_mode_flag(config.has(option::cli_limit_mode));
|
||||||
runtime->run(gen, ld, config.nasal_vm_args);
|
runtime->run(gen, ld, config.nasal_vm_args);
|
||||||
|
gc_time_ms = runtime->get_gc_time_ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
// get running time
|
// get running time
|
||||||
const auto end = clk::now();
|
const auto end = clk::now();
|
||||||
if (config.has(option::cli_show_execute_time)) {
|
if (config.has(option::cli_show_execute_time)) {
|
||||||
|
double execute_time_sec = static_cast<f64>((end - start).count())/den;
|
||||||
|
double gc_time_sec = gc_time_ms / 1000.0;
|
||||||
std::clog << "process exited after ";
|
std::clog << "process exited after ";
|
||||||
std::clog << static_cast<f64>((end-start).count())/den << "s.\n\n";
|
std::clog << execute_time_sec << "s, gc time: ";
|
||||||
|
std::clog << gc_time_sec << "s (";
|
||||||
|
std::clog << gc_time_sec / execute_time_sec * 100.0 << "%)\n\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 main(i32 argc, const char* argv[]) {
|
i32 main(i32 argc, const char* argv[]) {
|
||||||
// output version info
|
// output version info
|
||||||
if (argc<=1) {
|
if (argc <= 1) {
|
||||||
std::clog << logo;
|
std::clog << nasal::cli::logo;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,11 +119,11 @@ i32 main(i32 argc, const char* argv[]) {
|
||||||
const auto config = nasal::cli::parse({argv+1, argv+argc});
|
const auto config = nasal::cli::parse({argv+1, argv+argc});
|
||||||
|
|
||||||
// run directly or show help
|
// run directly or show help
|
||||||
if (argc==2) {
|
if (argc == 2) {
|
||||||
if (config.has(nasal::cli::option::cli_help)) {
|
if (config.has(nasal::cli::option::cli_help)) {
|
||||||
std::clog << nasal::cli::help;
|
std::clog << nasal::cli::help;
|
||||||
} else if (config.has(nasal::cli::option::cli_version)) {
|
} else if (config.has(nasal::cli::option::cli_version)) {
|
||||||
std::clog << version;
|
std::clog << nasal::cli::version;
|
||||||
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
|
} else if (config.has(nasal::cli::option::cli_repl_mode)) {
|
||||||
auto repl = std::make_unique<nasal::repl::repl>();
|
auto repl = std::make_unique<nasal::repl::repl>();
|
||||||
repl->execute();
|
repl->execute();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef __nasver__
|
#ifndef __nasver__
|
||||||
#define __nasver__ "11.3.1"
|
#define __nasver__ "11.3.2"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
|
@ -120,12 +120,14 @@ public:
|
||||||
class number_literal: public expr {
|
class number_literal: public expr {
|
||||||
private:
|
private:
|
||||||
f64 number;
|
f64 number;
|
||||||
|
std::string raw_text;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
number_literal(const span& location, const f64 num):
|
number_literal(const span& location, const f64 num, const std::string& raw):
|
||||||
expr(location, expr_type::ast_num), number(num) {}
|
expr(location, expr_type::ast_num), number(num), raw_text(raw) {}
|
||||||
~number_literal() override = default;
|
~number_literal() override = default;
|
||||||
f64 get_number() const {return number;}
|
f64 get_number() const { return number; }
|
||||||
|
const std::string& get_raw_text() const { return raw_text; }
|
||||||
void accept(ast_visitor*) override;
|
void accept(ast_visitor*) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,12 @@ public:
|
||||||
void context_change(nas_co*);
|
void context_change(nas_co*);
|
||||||
void context_reserve();
|
void context_reserve();
|
||||||
|
|
||||||
|
public:
|
||||||
|
double get_gc_time_ms() const {
|
||||||
|
const auto den = std::chrono::high_resolution_clock::duration::period::den;
|
||||||
|
return worktime * 1.0 / den * 1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
var newstr(char c) {
|
var newstr(char c) {
|
||||||
var s = alloc(vm_type::vm_str);
|
var s = alloc(vm_type::vm_str);
|
||||||
|
|
|
@ -235,7 +235,8 @@ nil_expr* parse::nil() {
|
||||||
number_literal* parse::num() {
|
number_literal* parse::num() {
|
||||||
auto node = new number_literal(
|
auto node = new number_literal(
|
||||||
toks[ptr].loc,
|
toks[ptr].loc,
|
||||||
util::str_to_num(toks[ptr].str.c_str())
|
util::str_to_num(toks[ptr].str.c_str()),
|
||||||
|
toks[ptr].str
|
||||||
);
|
);
|
||||||
match(tok::tk_num);
|
match(tok::tk_num);
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -6,22 +6,6 @@
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
var nas_vec::get_value(const i32 index) {
|
|
||||||
i32 size = elems.size();
|
|
||||||
if (index<-size || index>=size) {
|
|
||||||
return var::none();
|
|
||||||
}
|
|
||||||
return elems[index>=0? index:index+size];
|
|
||||||
}
|
|
||||||
|
|
||||||
var* nas_vec::get_memory(const i32 index) {
|
|
||||||
i32 size = elems.size();
|
|
||||||
if (index<-size || index>=size) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &elems[index>=0? index:index+size];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
||||||
if (!vec.elems.size() || vec.printed) {
|
if (!vec.elems.size() || vec.printed) {
|
||||||
out << (vec.elems.size()? "[..]":"[]");
|
out << (vec.elems.size()? "[..]":"[]");
|
||||||
|
@ -40,7 +24,8 @@ std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
||||||
var nas_hash::get_value(const std::string& key) {
|
var nas_hash::get_value(const std::string& key) {
|
||||||
if (elems.count(key)) {
|
if (elems.count(key)) {
|
||||||
return elems.at(key);
|
return elems.at(key);
|
||||||
} else if (!elems.count("parents")) {
|
}
|
||||||
|
if (!elems.count("parents")) {
|
||||||
return var::none();
|
return var::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +48,8 @@ var nas_hash::get_value(const std::string& key) {
|
||||||
var* nas_hash::get_memory(const std::string& key) {
|
var* nas_hash::get_memory(const std::string& key) {
|
||||||
if (elems.count(key)) {
|
if (elems.count(key)) {
|
||||||
return &elems.at(key);
|
return &elems.at(key);
|
||||||
} else if (!elems.count("parents")) {
|
}
|
||||||
|
if (!elems.count("parents")) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +265,6 @@ void nas_val::clear() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f64 var::to_num() const {
|
|
||||||
return type != vm_type::vm_str
|
|
||||||
? val.num
|
|
||||||
: util::str_to_num(str().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string var::to_str() {
|
std::string var::to_str() {
|
||||||
if (type==vm_type::vm_str) {
|
if (type==vm_type::vm_str) {
|
||||||
return str();
|
return str();
|
||||||
|
@ -317,41 +297,4 @@ std::ostream& operator<<(std::ostream& out, var& ref) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool var::object_check(const std::string& name) const {
|
|
||||||
return is_ghost() && ghost().type_name == name && ghost().pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::none() {
|
|
||||||
return {vm_type::vm_none, static_cast<u64>(0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::nil() {
|
|
||||||
return {vm_type::vm_nil, static_cast<u64>(0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::ret(u64 pc) {
|
|
||||||
return {vm_type::vm_ret, pc};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::cnt(i64 n) {
|
|
||||||
return {vm_type::vm_cnt, n};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::num(f64 n) {
|
|
||||||
return {vm_type::vm_num, n};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::gcobj(nas_val* p) {
|
|
||||||
return {p->type, p};
|
|
||||||
}
|
|
||||||
|
|
||||||
var var::addr(var* p) {
|
|
||||||
return {vm_type::vm_addr, p};
|
|
||||||
}
|
|
||||||
|
|
||||||
var nas_err(const std::string& error_function_name, const std::string& info) {
|
|
||||||
std::cerr << "[vm] " << error_function_name << ": " << info << "\n";
|
|
||||||
return var::none();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
124
src/nasal_type.h
124
src/nasal_type.h
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nasal.h"
|
#include "nasal.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -86,31 +87,45 @@ public:
|
||||||
} val;
|
} val;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
var(vm_type t, u64 pc) {type = t; val.ret = pc;}
|
var(vm_type t, u64 pc) { type = t; val.ret = pc; }
|
||||||
var(vm_type t, i64 ct) {type = t; val.cnt = ct;}
|
var(vm_type t, i64 ct) { type = t; val.cnt = ct; }
|
||||||
var(vm_type t, f64 n) {type = t; val.num = n;}
|
var(vm_type t, f64 n) { type = t; val.num = n; }
|
||||||
var(vm_type t, var* p) {type = t; val.addr = p;}
|
var(vm_type t, var* p) { type = t; val.addr = p; }
|
||||||
var(vm_type t, nas_val* p) {type = t; val.gcobj = p;}
|
var(vm_type t, nas_val* p) { type = t; val.gcobj = p; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
var() = default;
|
var() = default;
|
||||||
var(const var&) = default;
|
var(const var&) = default;
|
||||||
bool operator==(const var& nr) const {
|
bool operator==(const var& nr) const {
|
||||||
return type==nr.type && val.gcobj==nr.val.gcobj;
|
return type == nr.type && val.gcobj == nr.val.gcobj;
|
||||||
}
|
}
|
||||||
bool operator!=(const var& nr) const {
|
bool operator!=(const var& nr) const {
|
||||||
return type!=nr.type || val.gcobj!=nr.val.gcobj;
|
return type != nr.type || val.gcobj != nr.val.gcobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// create new var object
|
// create new var object
|
||||||
static var none();
|
static var none() {
|
||||||
static var nil();
|
return var(vm_type::vm_none, static_cast<u64>(0));
|
||||||
static var ret(u64);
|
}
|
||||||
static var cnt(i64);
|
static var nil() {
|
||||||
static var num(f64);
|
return var(vm_type::vm_nil, static_cast<u64>(0));
|
||||||
static var gcobj(nas_val*);
|
}
|
||||||
static var addr(var*);
|
static var ret(u64 pc) {
|
||||||
|
return var(vm_type::vm_ret, pc);
|
||||||
|
}
|
||||||
|
static var cnt(i64 n) {
|
||||||
|
return var(vm_type::vm_cnt, n);
|
||||||
|
}
|
||||||
|
static var num(f64 n) {
|
||||||
|
return var(vm_type::vm_num, n);
|
||||||
|
}
|
||||||
|
static var gcobj(nas_val* p) {
|
||||||
|
return var(p->type, p);
|
||||||
|
}
|
||||||
|
static var addr(var* p) {
|
||||||
|
return var(vm_type::vm_addr, p);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// get value
|
// get value
|
||||||
|
@ -143,26 +158,32 @@ public:
|
||||||
const nas_map& map() const { return *val.gcobj->ptr.map; }
|
const nas_map& map() const { return *val.gcobj->ptr.map; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool is_none() const { return type==vm_type::vm_none; }
|
bool is_none() const { return type == vm_type::vm_none; }
|
||||||
bool is_cnt() const { return type==vm_type::vm_cnt; }
|
bool is_cnt() const { return type == vm_type::vm_cnt; }
|
||||||
bool is_addr() const { return type==vm_type::vm_addr; }
|
bool is_addr() const { return type == vm_type::vm_addr; }
|
||||||
bool is_ret() const { return type==vm_type::vm_ret; }
|
bool is_ret() const { return type == vm_type::vm_ret; }
|
||||||
bool is_nil() const { return type==vm_type::vm_nil; }
|
bool is_nil() const { return type == vm_type::vm_nil; }
|
||||||
bool is_num() const { return type==vm_type::vm_num; }
|
bool is_num() const { return type == vm_type::vm_num; }
|
||||||
bool is_str() const { return type==vm_type::vm_str; }
|
bool is_str() const { return type == vm_type::vm_str; }
|
||||||
bool is_vec() const { return type==vm_type::vm_vec; }
|
bool is_vec() const { return type == vm_type::vm_vec; }
|
||||||
bool is_hash() const { return type==vm_type::vm_hash; }
|
bool is_hash() const { return type == vm_type::vm_hash; }
|
||||||
bool is_func() const { return type==vm_type::vm_func; }
|
bool is_func() const { return type == vm_type::vm_func; }
|
||||||
bool is_upval() const { return type==vm_type::vm_upval; }
|
bool is_upval() const { return type == vm_type::vm_upval; }
|
||||||
bool is_ghost() const { return type==vm_type::vm_ghost; }
|
bool is_ghost() const { return type == vm_type::vm_ghost; }
|
||||||
bool is_coroutine() const { return type==vm_type::vm_co; }
|
bool is_coroutine() const { return type == vm_type::vm_co; }
|
||||||
bool is_map() const { return type==vm_type::vm_map; }
|
bool is_map() const { return type == vm_type::vm_map; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// number and string can be translated to each other
|
// convert to number
|
||||||
f64 to_num() const;
|
f64 to_num() const {
|
||||||
|
return type != vm_type::vm_str
|
||||||
|
? val.num
|
||||||
|
: util::str_to_num(str().c_str());
|
||||||
|
}
|
||||||
|
// convert to string
|
||||||
std::string to_str();
|
std::string to_str();
|
||||||
bool object_check(const std::string&) const;
|
inline bool object_check(const std::string&) const;
|
||||||
|
friend std::ostream& operator<<(std::ostream&, var&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_vec {
|
struct nas_vec {
|
||||||
|
@ -172,8 +193,21 @@ struct nas_vec {
|
||||||
bool printed = false;
|
bool printed = false;
|
||||||
|
|
||||||
auto size() const { return elems.size(); }
|
auto size() const { return elems.size(); }
|
||||||
var get_value(const i32);
|
var get_value(const i32 index) {
|
||||||
var* get_memory(const i32);
|
i32 size = elems.size();
|
||||||
|
if (index < -size || index >= size) {
|
||||||
|
return var::none();
|
||||||
|
}
|
||||||
|
return elems[index >= 0 ? index : index + size];
|
||||||
|
}
|
||||||
|
var* get_memory(const i32 index) {
|
||||||
|
i32 size = elems.size();
|
||||||
|
if (index < -size || index >= size) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &elems[index >= 0 ? index : index + size];
|
||||||
|
}
|
||||||
|
friend std::ostream& operator<<(std::ostream&, nas_vec&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_hash {
|
struct nas_hash {
|
||||||
|
@ -185,6 +219,7 @@ struct nas_hash {
|
||||||
auto size() const { return elems.size(); }
|
auto size() const { return elems.size(); }
|
||||||
var get_value(const std::string&);
|
var get_value(const std::string&);
|
||||||
var* get_memory(const std::string&);
|
var* get_memory(const std::string&);
|
||||||
|
friend std::ostream& operator<<(std::ostream&, nas_hash&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_func {
|
struct nas_func {
|
||||||
|
@ -206,6 +241,7 @@ struct nas_func {
|
||||||
parameter_size(0), local_size(0),
|
parameter_size(0), local_size(0),
|
||||||
dynamic_parameter_name("") {}
|
dynamic_parameter_name("") {}
|
||||||
void clear();
|
void clear();
|
||||||
|
friend std::ostream& operator<<(std::ostream&, nas_func&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_upval {
|
struct nas_upval {
|
||||||
|
@ -222,7 +258,7 @@ public:
|
||||||
nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {}
|
nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {}
|
||||||
|
|
||||||
var& operator[](usize n) {
|
var& operator[](usize n) {
|
||||||
return on_stack? stack_frame_offset[n]:elems[n];
|
return on_stack? stack_frame_offset[n] : elems[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
@ -250,6 +286,7 @@ public:
|
||||||
~nas_ghost() { clear(); }
|
~nas_ghost() { clear(); }
|
||||||
void set(const std::string&, destructor, marker, void*);
|
void set(const std::string&, destructor, marker, void*);
|
||||||
void clear();
|
void clear();
|
||||||
|
friend std::ostream& operator<<(std::ostream&, const nas_ghost&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const auto& get_ghost_name() const { return type_name; }
|
const auto& get_ghost_name() const { return type_name; }
|
||||||
|
@ -290,6 +327,7 @@ struct nas_co {
|
||||||
delete[] ctx.stack;
|
delete[] ctx.stack;
|
||||||
}
|
}
|
||||||
void clear();
|
void clear();
|
||||||
|
friend std::ostream& operator<<(std::ostream&, const nas_co&);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nas_map {
|
struct nas_map {
|
||||||
|
@ -304,21 +342,21 @@ public:
|
||||||
|
|
||||||
var get_value(const std::string&);
|
var get_value(const std::string&);
|
||||||
var* get_memory(const std::string&);
|
var* get_memory(const std::string&);
|
||||||
|
friend std::ostream& operator<<(std::ostream&, nas_map&);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream&, nas_vec&);
|
|
||||||
std::ostream& operator<<(std::ostream&, nas_hash&);
|
|
||||||
std::ostream& operator<<(std::ostream&, nas_func&);
|
|
||||||
std::ostream& operator<<(std::ostream&, nas_map&);
|
|
||||||
std::ostream& operator<<(std::ostream&, const nas_ghost&);
|
|
||||||
std::ostream& operator<<(std::ostream&, const nas_co&);
|
|
||||||
std::ostream& operator<<(std::ostream&, var&);
|
|
||||||
|
|
||||||
const var zero = var::num(0);
|
const var zero = var::num(0);
|
||||||
const var one = var::num(1);
|
const var one = var::num(1);
|
||||||
const var nil = var::nil();
|
const var nil = var::nil();
|
||||||
|
|
||||||
|
inline bool var::object_check(const std::string& name) const {
|
||||||
|
return is_ghost() && ghost().type_name == name && ghost().pointer;
|
||||||
|
}
|
||||||
|
|
||||||
// use to print error log and return error value
|
// use to print error log and return error value
|
||||||
var nas_err(const std::string&, const std::string&);
|
static var nas_err(const std::string& func, const std::string& info) {
|
||||||
|
std::cerr << "[vm] " << func << ": " << info << "\n";
|
||||||
|
return var::none();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -226,7 +226,7 @@ void vm::function_call_trace() {
|
||||||
std::stack<u64> callsite;
|
std::stack<u64> callsite;
|
||||||
|
|
||||||
// load call trace
|
// load call trace
|
||||||
for(var* i = bottom; i<=top; ++i) {
|
for(var* i = bottom; i <= top; ++i) {
|
||||||
// i-1 is the callsite program counter of this function
|
// i-1 is the callsite program counter of this function
|
||||||
if (i->is_addr() && i+2<=top &&
|
if (i->is_addr() && i+2<=top &&
|
||||||
(i+1)->is_ret() && (i+1)->ret()>0 &&
|
(i+1)->is_ret() && (i+1)->ret()>0 &&
|
||||||
|
@ -238,7 +238,7 @@ void vm::function_call_trace() {
|
||||||
|
|
||||||
// another condition may exist
|
// another condition may exist
|
||||||
// have ret pc on stack, but no function at the top of the ret pc
|
// have ret pc on stack, but no function at the top of the ret pc
|
||||||
for(var * i = top; i>=bottom; --i) {
|
for(var * i = top; i >= bottom; --i) {
|
||||||
if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) ||
|
if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) ||
|
||||||
(i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) {
|
(i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) {
|
||||||
functions.push(&ctx.funcr.func());
|
functions.push(&ctx.funcr.func());
|
||||||
|
@ -254,7 +254,7 @@ void vm::function_call_trace() {
|
||||||
|
|
||||||
std::clog << "\ncall trace ";
|
std::clog << "\ncall trace ";
|
||||||
std::clog << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
std::clog << (ngc.cort? "(coroutine)":"(main)") << "\n";
|
||||||
std::clog << " crash occurred in\n ";
|
std::clog << " crash occurred at\n ";
|
||||||
function_detail_info(ctx.funcr.func());
|
function_detail_info(ctx.funcr.func());
|
||||||
std::clog << " at " << files[bytecode[ctx.pc].fidx] << ":";
|
std::clog << " at " << files[bytecode[ctx.pc].fidx] << ":";
|
||||||
std::clog << bytecode[ctx.pc].line << "\n";
|
std::clog << bytecode[ctx.pc].line << "\n";
|
||||||
|
@ -325,7 +325,7 @@ void vm::trace_back() {
|
||||||
// the first called place has no same calls
|
// the first called place has no same calls
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::stack_info(const u64 limit = 16) {
|
void vm::stack_info(const u64 limit) {
|
||||||
var* top = ctx.top;
|
var* top = ctx.top;
|
||||||
var* bottom = ctx.stack;
|
var* bottom = ctx.stack;
|
||||||
const auto stack_address = reinterpret_cast<u64>(bottom);
|
const auto stack_address = reinterpret_cast<u64>(bottom);
|
||||||
|
@ -525,8 +525,16 @@ std::string vm::type_name_string(const var& value) const {
|
||||||
void vm::die(const std::string& str) {
|
void vm::die(const std::string& str) {
|
||||||
std::cerr << "[vm] error: " << str << "\n";
|
std::cerr << "[vm] error: " << str << "\n";
|
||||||
function_call_trace();
|
function_call_trace();
|
||||||
trace_back();
|
|
||||||
stack_info();
|
// trace back contains bytecode info, dump in verbose mode
|
||||||
|
if (verbose) {
|
||||||
|
trace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// verbose will dump more values on stack
|
||||||
|
if (verbose) {
|
||||||
|
stack_info(64);
|
||||||
|
}
|
||||||
|
|
||||||
// show verbose crash info
|
// show verbose crash info
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -534,14 +542,17 @@ void vm::die(const std::string& str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ngc.cort) {
|
if (!ngc.cort) {
|
||||||
|
if (!verbose) {
|
||||||
|
std::cerr << "\n[vm] use <-d> for detailed crash info.\n\n";
|
||||||
|
}
|
||||||
// in main context, exit directly
|
// in main context, exit directly
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
} else {
|
|
||||||
// in coroutine, shut down the coroutine and return to main context
|
|
||||||
ctx.pc = 0; // mark coroutine 'dead'
|
|
||||||
ngc.context_reserve(); // switch context to main
|
|
||||||
ctx.top[0] = nil; // generate return value 'nil'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in coroutine, shut down the coroutine and return to main context
|
||||||
|
ctx.pc = 0; // mark coroutine 'dead'
|
||||||
|
ngc.context_reserve(); // switch context to main
|
||||||
|
ctx.top[0] = nil; // generate return value 'nil'
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm::run(const codegen& gen,
|
void vm::run(const codegen& gen,
|
||||||
|
|
204
src/nasal_vm.h
204
src/nasal_vm.h
|
@ -97,6 +97,7 @@ protected:
|
||||||
protected:
|
protected:
|
||||||
/* vm calculation functions*/
|
/* vm calculation functions*/
|
||||||
inline bool boolify(const var&);
|
inline bool boolify(const var&);
|
||||||
|
inline void set_frame(const nas_func&, var*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* vm operands */
|
/* vm operands */
|
||||||
|
@ -325,6 +326,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool>* interrupt_ptr = nullptr;
|
std::atomic<bool>* interrupt_ptr = nullptr;
|
||||||
|
auto get_gc_time_ms() const {
|
||||||
|
return ngc.get_gc_time_ms();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool vm::boolify(const var& val) {
|
inline bool vm::boolify(const var& val) {
|
||||||
|
@ -345,6 +349,15 @@ inline bool vm::boolify(const var& val) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void vm::set_frame(const nas_func& func, var* local) {
|
||||||
|
ctx.top[0] = ctx.upvalr;
|
||||||
|
(++ctx.top)[0] = var::addr(ctx.localr);
|
||||||
|
(++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret
|
||||||
|
ctx.pc = func.entry - 1;
|
||||||
|
ctx.localr = local;
|
||||||
|
ctx.upvalr = nil;
|
||||||
|
}
|
||||||
|
|
||||||
inline void vm::o_repl() {
|
inline void vm::o_repl() {
|
||||||
// reserved for repl mode stack top value output
|
// reserved for repl mode stack top value output
|
||||||
if (allow_repl_output) {
|
if (allow_repl_output) {
|
||||||
|
@ -366,8 +379,8 @@ inline void vm::o_loadl() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_loadu() {
|
inline void vm::o_loadu() {
|
||||||
ctx.funcr.func().upval[(imm[ctx.pc]>>16)&0xffff]
|
ctx.funcr.func().upval[(imm[ctx.pc]>>16) & 0xffff]
|
||||||
.upval()[imm[ctx.pc]&0xffff] = (ctx.top--)[0];
|
.upval()[imm[ctx.pc] & 0xffff] = (ctx.top--)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_dup() {
|
inline void vm::o_dup() {
|
||||||
|
@ -459,7 +472,7 @@ inline void vm::o_lnot() {
|
||||||
var val = ctx.top[0];
|
var val = ctx.top[0];
|
||||||
switch(val.type) {
|
switch(val.type) {
|
||||||
case vm_type::vm_nil: ctx.top[0] = one; break;
|
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_num: ctx.top[0] = val.num()? zero : one; break;
|
||||||
case vm_type::vm_str: {
|
case vm_type::vm_str: {
|
||||||
const f64 num = util::str_to_num(val.str().c_str());
|
const f64 num = util::str_to_num(val.str().c_str());
|
||||||
if (std::isnan(num)) {
|
if (std::isnan(num)) {
|
||||||
|
@ -469,7 +482,7 @@ inline void vm::o_lnot() {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
die("cannot do not-operation on "+type_name_string(val));
|
die("cannot do not-operation on " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,7 +497,7 @@ inline void vm::o_bnot() {
|
||||||
|
|
||||||
inline void vm::o_btor() {
|
inline void vm::o_btor() {
|
||||||
ctx.top[-1] = var::num(
|
ctx.top[-1] = var::num(
|
||||||
static_cast<i32>(ctx.top[-1].to_num())|
|
static_cast<i32>(ctx.top[-1].to_num()) |
|
||||||
static_cast<i32>(ctx.top[0].to_num())
|
static_cast<i32>(ctx.top[0].to_num())
|
||||||
);
|
);
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
@ -492,7 +505,7 @@ inline void vm::o_btor() {
|
||||||
|
|
||||||
inline void vm::o_btxor() {
|
inline void vm::o_btxor() {
|
||||||
ctx.top[-1] = var::num(
|
ctx.top[-1] = var::num(
|
||||||
static_cast<i32>(ctx.top[-1].to_num())^
|
static_cast<i32>(ctx.top[-1].to_num()) ^
|
||||||
static_cast<i32>(ctx.top[0].to_num())
|
static_cast<i32>(ctx.top[0].to_num())
|
||||||
);
|
);
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
@ -500,7 +513,7 @@ inline void vm::o_btxor() {
|
||||||
|
|
||||||
inline void vm::o_btand() {
|
inline void vm::o_btand() {
|
||||||
ctx.top[-1] = var::num(
|
ctx.top[-1] = var::num(
|
||||||
static_cast<i32>(ctx.top[-1].to_num())&
|
static_cast<i32>(ctx.top[-1].to_num()) &
|
||||||
static_cast<i32>(ctx.top[0].to_num())
|
static_cast<i32>(ctx.top[0].to_num())
|
||||||
);
|
);
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
@ -510,18 +523,18 @@ inline void vm::o_btand() {
|
||||||
ctx.top[-1] = var::num(ctx.top[-1].to_num() type ctx.top[0].to_num());\
|
ctx.top[-1] = var::num(ctx.top[-1].to_num() type ctx.top[0].to_num());\
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
|
||||||
inline void vm::o_add() {op_calc(+);}
|
inline void vm::o_add() { op_calc(+); }
|
||||||
inline void vm::o_sub() {op_calc(-);}
|
inline void vm::o_sub() { op_calc(-); }
|
||||||
inline void vm::o_mul() {op_calc(*);}
|
inline void vm::o_mul() { op_calc(*); }
|
||||||
inline void vm::o_div() {op_calc(/);}
|
inline void vm::o_div() { op_calc(/); }
|
||||||
inline void vm::o_lnk() {
|
inline void vm::o_lnk() {
|
||||||
// concat two vectors into one
|
// concat two vectors into one
|
||||||
if (ctx.top[-1].is_vec() && ctx.top[0].is_vec()) {
|
if (ctx.top[-1].is_vec() && ctx.top[0].is_vec()) {
|
||||||
ngc.temp = ngc.alloc(vm_type::vm_vec);
|
ngc.temp = ngc.alloc(vm_type::vm_vec);
|
||||||
for(auto i : ctx.top[-1].vec().elems) {
|
for(auto& i : ctx.top[-1].vec().elems) {
|
||||||
ngc.temp.vec().elems.push_back(i);
|
ngc.temp.vec().elems.push_back(i);
|
||||||
}
|
}
|
||||||
for(auto i : ctx.top[0].vec().elems) {
|
for(auto& i : ctx.top[0].vec().elems) {
|
||||||
ngc.temp.vec().elems.push_back(i);
|
ngc.temp.vec().elems.push_back(i);
|
||||||
}
|
}
|
||||||
ctx.top[-1] = ngc.temp;
|
ctx.top[-1] = ngc.temp;
|
||||||
|
@ -530,19 +543,19 @@ inline void vm::o_lnk() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// concat strings
|
// concat strings
|
||||||
ctx.top[-1] = ngc.newstr(ctx.top[-1].to_str()+ctx.top[0].to_str());
|
ctx.top[-1] = ngc.newstr(ctx.top[-1].to_str() + ctx.top[0].to_str());
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define op_calc_const(type)\
|
#define op_calc_const(type)\
|
||||||
ctx.top[0] = var::num(ctx.top[0].to_num() type const_number[imm[ctx.pc]]);
|
ctx.top[0] = var::num(ctx.top[0].to_num() type const_number[imm[ctx.pc]]);
|
||||||
|
|
||||||
inline void vm::o_addc() {op_calc_const(+);}
|
inline void vm::o_addc() { op_calc_const(+); }
|
||||||
inline void vm::o_subc() {op_calc_const(-);}
|
inline void vm::o_subc() { op_calc_const(-); }
|
||||||
inline void vm::o_mulc() {op_calc_const(*);}
|
inline void vm::o_mulc() { op_calc_const(*); }
|
||||||
inline void vm::o_divc() {op_calc_const(/);}
|
inline void vm::o_divc() { op_calc_const(/); }
|
||||||
inline void vm::o_lnkc() {
|
inline void vm::o_lnkc() {
|
||||||
ctx.top[0] = ngc.newstr(ctx.top[0].to_str()+const_string[imm[ctx.pc]]);
|
ctx.top[0] = ngc.newstr(ctx.top[0].to_str() + const_string[imm[ctx.pc]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// top[0] stores the value of memr[0], to avoid being garbage-collected
|
// top[0] stores the value of memr[0], to avoid being garbage-collected
|
||||||
|
@ -555,12 +568,12 @@ inline void vm::o_lnkc() {
|
||||||
ctx.memr[0].to_num() type ctx.top[-1].to_num()\
|
ctx.memr[0].to_num() type ctx.top[-1].to_num()\
|
||||||
);\
|
);\
|
||||||
ctx.memr = nullptr;\
|
ctx.memr = nullptr;\
|
||||||
ctx.top -= imm[ctx.pc]+1;
|
ctx.top -= imm[ctx.pc] + 1;
|
||||||
|
|
||||||
inline void vm::o_addeq() {op_calc_eq(+);}
|
inline void vm::o_addeq() { op_calc_eq(+); }
|
||||||
inline void vm::o_subeq() {op_calc_eq(-);}
|
inline void vm::o_subeq() { op_calc_eq(-); }
|
||||||
inline void vm::o_muleq() {op_calc_eq(*);}
|
inline void vm::o_muleq() { op_calc_eq(*); }
|
||||||
inline void vm::o_diveq() {op_calc_eq(/);}
|
inline void vm::o_diveq() { op_calc_eq(/); }
|
||||||
inline void vm::o_lnkeq() {
|
inline void vm::o_lnkeq() {
|
||||||
// concat two vectors into one
|
// concat two vectors into one
|
||||||
if (ctx.top[-1].is_vec() && ctx.memr[0].is_vec()) {
|
if (ctx.top[-1].is_vec() && ctx.memr[0].is_vec()) {
|
||||||
|
@ -579,10 +592,10 @@ inline void vm::o_lnkeq() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.top[-1] = ctx.memr[0] = ngc.newstr(
|
ctx.top[-1] = ctx.memr[0] = ngc.newstr(
|
||||||
ctx.memr[0].to_str()+ctx.top[-1].to_str()
|
ctx.memr[0].to_str() + ctx.top[-1].to_str()
|
||||||
);
|
);
|
||||||
ctx.memr = nullptr;
|
ctx.memr = nullptr;
|
||||||
ctx.top -= imm[ctx.pc]+1;
|
ctx.top -= imm[ctx.pc] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_bandeq() {
|
inline void vm::o_bandeq() {
|
||||||
|
@ -605,11 +618,11 @@ inline void vm::o_boreq() {
|
||||||
|
|
||||||
inline void vm::o_bxoreq() {
|
inline void vm::o_bxoreq() {
|
||||||
ctx.top[-1] = ctx.memr[0] = var::num(
|
ctx.top[-1] = ctx.memr[0] = var::num(
|
||||||
static_cast<i32>(ctx.memr[0].to_num())^
|
static_cast<i32>(ctx.memr[0].to_num()) ^
|
||||||
static_cast<i32>(ctx.top[-1].to_num())
|
static_cast<i32>(ctx.top[-1].to_num())
|
||||||
);
|
);
|
||||||
ctx.memr = nullptr;
|
ctx.memr = nullptr;
|
||||||
ctx.top -= imm[ctx.pc]+1;
|
ctx.top -= imm[ctx.pc] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// top[0] stores the value of memr[0], to avoid being garbage-collected
|
// top[0] stores the value of memr[0], to avoid being garbage-collected
|
||||||
|
@ -623,13 +636,13 @@ inline void vm::o_bxoreq() {
|
||||||
);\
|
);\
|
||||||
ctx.memr = nullptr;
|
ctx.memr = nullptr;
|
||||||
|
|
||||||
inline void vm::o_addeqc() {op_calc_eq_const(+);}
|
inline void vm::o_addeqc() { op_calc_eq_const(+); }
|
||||||
inline void vm::o_subeqc() {op_calc_eq_const(-);}
|
inline void vm::o_subeqc() { op_calc_eq_const(-); }
|
||||||
inline void vm::o_muleqc() {op_calc_eq_const(*);}
|
inline void vm::o_muleqc() { op_calc_eq_const(*); }
|
||||||
inline void vm::o_diveqc() {op_calc_eq_const(/);}
|
inline void vm::o_diveqc() { op_calc_eq_const(/); }
|
||||||
inline void vm::o_lnkeqc() {
|
inline void vm::o_lnkeqc() {
|
||||||
ctx.top[0] = ctx.memr[0] = ngc.newstr(
|
ctx.top[0] = ctx.memr[0] = ngc.newstr(
|
||||||
ctx.memr[0].to_str()+const_string[imm[ctx.pc]]
|
ctx.memr[0].to_str() + const_string[imm[ctx.pc]]
|
||||||
);
|
);
|
||||||
ctx.memr = nullptr;
|
ctx.memr = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -641,13 +654,13 @@ inline void vm::o_lnkeqc() {
|
||||||
ctx.memr = nullptr;\
|
ctx.memr = nullptr;\
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
|
||||||
inline void vm::o_addecp() {op_calc_eq_const_and_pop(+);}
|
inline void vm::o_addecp() { op_calc_eq_const_and_pop(+); }
|
||||||
inline void vm::o_subecp() {op_calc_eq_const_and_pop(-);}
|
inline void vm::o_subecp() { op_calc_eq_const_and_pop(-); }
|
||||||
inline void vm::o_mulecp() {op_calc_eq_const_and_pop(*);}
|
inline void vm::o_mulecp() { op_calc_eq_const_and_pop(*); }
|
||||||
inline void vm::o_divecp() {op_calc_eq_const_and_pop(/);}
|
inline void vm::o_divecp() { op_calc_eq_const_and_pop(/); }
|
||||||
inline void vm::o_lnkecp() {
|
inline void vm::o_lnkecp() {
|
||||||
ctx.top[0] = ctx.memr[0] = ngc.newstr(
|
ctx.top[0] = ctx.memr[0] = ngc.newstr(
|
||||||
ctx.memr[0].to_str()+const_string[imm[ctx.pc]]
|
ctx.memr[0].to_str() + const_string[imm[ctx.pc]]
|
||||||
);
|
);
|
||||||
ctx.memr = nullptr;
|
ctx.memr = nullptr;
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
|
@ -670,12 +683,12 @@ inline void vm::o_eq() {
|
||||||
if (val1.is_nil() && val2.is_nil()) {
|
if (val1.is_nil() && val2.is_nil()) {
|
||||||
ctx.top[0] = one;
|
ctx.top[0] = one;
|
||||||
} else if (val1.is_str() && val2.is_str()) {
|
} else if (val1.is_str() && val2.is_str()) {
|
||||||
ctx.top[0] = (val1.str()==val2.str())? one:zero;
|
ctx.top[0] = (val1.str()==val2.str())? one : zero;
|
||||||
} else if ((val1.is_num() || val2.is_num())
|
} else if ((val1.is_num() || val2.is_num())
|
||||||
&& !val1.is_nil() && !val2.is_nil()) {
|
&& !val1.is_nil() && !val2.is_nil()) {
|
||||||
ctx.top[0] = (val1.to_num()==val2.to_num())? one:zero;
|
ctx.top[0] = (val1.to_num()==val2.to_num())? one : zero;
|
||||||
} else {
|
} else {
|
||||||
ctx.top[0] = (val1==val2)? one:zero;
|
ctx.top[0] = (val1==val2)? one : zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,59 +698,59 @@ inline void vm::o_neq() {
|
||||||
if (val1.is_nil() && val2.is_nil()) {
|
if (val1.is_nil() && val2.is_nil()) {
|
||||||
ctx.top[0] = zero;
|
ctx.top[0] = zero;
|
||||||
} else if (val1.is_str() && val2.is_str()) {
|
} else if (val1.is_str() && val2.is_str()) {
|
||||||
ctx.top[0] = (val1.str()!=val2.str())? one:zero;
|
ctx.top[0] = (val1.str()!=val2.str())? one : zero;
|
||||||
} else if ((val1.is_num() || val2.is_num())
|
} else if ((val1.is_num() || val2.is_num())
|
||||||
&& !val1.is_nil() && !val2.is_nil()) {
|
&& !val1.is_nil() && !val2.is_nil()) {
|
||||||
ctx.top[0] = (val1.to_num()!=val2.to_num())? one:zero;
|
ctx.top[0] = (val1.to_num()!=val2.to_num())? one : zero;
|
||||||
} else {
|
} else {
|
||||||
ctx.top[0] = (val1!=val2)? one:zero;
|
ctx.top[0] = (val1!=val2)? one : zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define op_cmp(type)\
|
#define op_cmp(type)\
|
||||||
--ctx.top;\
|
--ctx.top;\
|
||||||
ctx.top[0] = (ctx.top[0].to_num() type ctx.top[1].to_num())? one:zero;
|
ctx.top[0] = (ctx.top[0].to_num() type ctx.top[1].to_num())? one : zero;
|
||||||
|
|
||||||
inline void vm::o_less() {op_cmp(<);}
|
inline void vm::o_less() { op_cmp(<); }
|
||||||
inline void vm::o_leq() {op_cmp(<=);}
|
inline void vm::o_leq() { op_cmp(<=); }
|
||||||
inline void vm::o_grt() {op_cmp(>);}
|
inline void vm::o_grt() { op_cmp(>); }
|
||||||
inline void vm::o_geq() {op_cmp(>=);}
|
inline void vm::o_geq() { op_cmp(>=); }
|
||||||
|
|
||||||
#define op_cmp_const(type)\
|
#define op_cmp_const(type)\
|
||||||
ctx.top[0] = (ctx.top[0].to_num() type const_number[imm[ctx.pc]])? one:zero;
|
ctx.top[0] = (ctx.top[0].to_num() type const_number[imm[ctx.pc]])? one : zero;
|
||||||
|
|
||||||
inline void vm::o_lessc() {op_cmp_const(<);}
|
inline void vm::o_lessc() { op_cmp_const(<); }
|
||||||
inline void vm::o_leqc() {op_cmp_const(<=);}
|
inline void vm::o_leqc() { op_cmp_const(<=); }
|
||||||
inline void vm::o_grtc() {op_cmp_const(>);}
|
inline void vm::o_grtc() { op_cmp_const(>); }
|
||||||
inline void vm::o_geqc() {op_cmp_const(>=);}
|
inline void vm::o_geqc() { op_cmp_const(>=); }
|
||||||
|
|
||||||
inline void vm::o_pop() {
|
inline void vm::o_pop() {
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_jmp() {
|
inline void vm::o_jmp() {
|
||||||
ctx.pc = imm[ctx.pc]-1;
|
ctx.pc = imm[ctx.pc] - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_jt() {
|
inline void vm::o_jt() {
|
||||||
// jump true needs to reserve the result on stack
|
// jump true needs to reserve the result on stack
|
||||||
// because conditional expression in nasal has return value
|
// because conditional expression in nasal has return value
|
||||||
if (boolify(ctx.top[0])) {
|
if (boolify(ctx.top[0])) {
|
||||||
ctx.pc = imm[ctx.pc]-1;
|
ctx.pc = imm[ctx.pc] - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_jf() {
|
inline void vm::o_jf() {
|
||||||
// jump false doesn't need to reserve result
|
// jump false doesn't need to reserve result
|
||||||
if (!boolify(ctx.top[0])) {
|
if (!boolify(ctx.top[0])) {
|
||||||
ctx.pc = imm[ctx.pc]-1;
|
ctx.pc = imm[ctx.pc] - 1;
|
||||||
}
|
}
|
||||||
--ctx.top;
|
--ctx.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_cnt() {
|
inline void vm::o_cnt() {
|
||||||
if (!ctx.top[0].is_vec()) {
|
if (!ctx.top[0].is_vec()) {
|
||||||
die("must use vector in forindex/foreach but get "+
|
die("must use vector in forindex/foreach but get " +
|
||||||
type_name_string(ctx.top[0])
|
type_name_string(ctx.top[0])
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -775,8 +788,8 @@ inline void vm::o_calll() {
|
||||||
|
|
||||||
inline void vm::o_upval() {
|
inline void vm::o_upval() {
|
||||||
(++ctx.top)[0] = ctx.funcr.func()
|
(++ctx.top)[0] = ctx.funcr.func()
|
||||||
.upval[(imm[ctx.pc]>>16)&0xffff]
|
.upval[(imm[ctx.pc] >> 16) & 0xffff]
|
||||||
.upval()[imm[ctx.pc]&0xffff];
|
.upval()[imm[ctx.pc] & 0xffff];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_callv() {
|
inline void vm::o_callv() {
|
||||||
|
@ -790,7 +803,7 @@ inline void vm::o_callv() {
|
||||||
}
|
}
|
||||||
} else if (vec.is_hash()) {
|
} else if (vec.is_hash()) {
|
||||||
if (!val.is_str()) {
|
if (!val.is_str()) {
|
||||||
die("must use string as the key but get "+type_name_string(val));
|
die("must use string as the key but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx.top[0] = vec.hash().get_value(val.str());
|
ctx.top[0] = vec.hash().get_value(val.str());
|
||||||
|
@ -809,20 +822,20 @@ inline void vm::o_callv() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx.top[0] = var::num(
|
ctx.top[0] = var::num(
|
||||||
static_cast<f64>(static_cast<u8>(str[num>=0? num:num+len]))
|
static_cast<f64>(static_cast<u8>(str[num>=0? num : num + len]))
|
||||||
);
|
);
|
||||||
} else if (vec.is_map()) {
|
} else if (vec.is_map()) {
|
||||||
if (!val.is_str()) {
|
if (!val.is_str()) {
|
||||||
die("must use string as the key but get "+type_name_string(val));
|
die("must use string as the key but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx.top[0] = vec.map().get_value(val.str());
|
ctx.top[0] = vec.map().get_value(val.str());
|
||||||
if (ctx.top[0].is_none()) {
|
if (ctx.top[0].is_none()) {
|
||||||
die("cannot find symbol \""+val.str()+"\"");
|
die("cannot find symbol \"" + val.str() + "\"");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
die("must call a vector/hash/string but get "+type_name_string(vec));
|
die("must call a vector/hash/string but get " + type_name_string(vec));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -830,7 +843,7 @@ inline void vm::o_callv() {
|
||||||
inline void vm::o_callvi() {
|
inline void vm::o_callvi() {
|
||||||
var val = ctx.top[0];
|
var val = ctx.top[0];
|
||||||
if (!val.is_vec()) {
|
if (!val.is_vec()) {
|
||||||
die("must use a vector but get "+type_name_string(val));
|
die("must use a vector but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// cannot use operator[], because this may cause overflow
|
// cannot use operator[], because this may cause overflow
|
||||||
|
@ -844,7 +857,7 @@ inline void vm::o_callvi() {
|
||||||
inline void vm::o_callh() {
|
inline void vm::o_callh() {
|
||||||
var val = ctx.top[0];
|
var val = ctx.top[0];
|
||||||
if (!val.is_hash() && !val.is_map()) {
|
if (!val.is_hash() && !val.is_map()) {
|
||||||
die("must call a hash but get "+type_name_string(val));
|
die("must call a hash but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,21 +867,26 @@ inline void vm::o_callh() {
|
||||||
} else {
|
} else {
|
||||||
ctx.top[0] = val.map().get_value(str);
|
ctx.top[0] = val.map().get_value(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// report key not found if get_value returns none
|
||||||
if (ctx.top[0].is_none()) {
|
if (ctx.top[0].is_none()) {
|
||||||
val.is_hash()?
|
val.is_hash()
|
||||||
die(report_key_not_found(str, val.hash())):
|
? die(report_key_not_found(str, val.hash()))
|
||||||
die("cannot find symbol \"" + str + "\"");
|
: die("cannot find symbol \"" + str + "\"");
|
||||||
return;
|
return;
|
||||||
} else if (ctx.top[0].is_func()) {
|
}
|
||||||
|
|
||||||
|
// if get function from hash, set 'me'
|
||||||
|
if (ctx.top[0].is_func() && val.is_hash()) {
|
||||||
ctx.top[0].func().local[0] = val; // 'me'
|
ctx.top[0].func().local[0] = val; // 'me'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_callfv() {
|
inline void vm::o_callfv() {
|
||||||
const auto argc = imm[ctx.pc]; // arguments counter
|
const auto argc = imm[ctx.pc]; // arguments counter
|
||||||
var* local = ctx.top-argc+1; // arguments begin address
|
var* local = ctx.top - argc + 1; // arguments begin address
|
||||||
if (!local[-1].is_func()) {
|
if (!local[-1].is_func()) {
|
||||||
die("must call a function but get "+type_name_string(local[-1]));
|
die("must call a function but get " + type_name_string(local[-1]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& func = local[-1].func();
|
const auto& func = local[-1].func();
|
||||||
|
@ -911,7 +929,7 @@ inline void vm::o_callfv() {
|
||||||
// then all the available values the vector needs
|
// then all the available values the vector needs
|
||||||
// are all outside the stack top and may be
|
// are all outside the stack top and may be
|
||||||
// collected incorrectly
|
// collected incorrectly
|
||||||
ctx.top = local+func.local_size;
|
ctx.top = local + func.local_size;
|
||||||
|
|
||||||
// use (std::min) to avoid compilation error in MSVC
|
// use (std::min) to avoid compilation error in MSVC
|
||||||
// MSVC windows.h uses macro std::min
|
// MSVC windows.h uses macro std::min
|
||||||
|
@ -924,25 +942,22 @@ inline void vm::o_callfv() {
|
||||||
local[0] = func.local[0]; // load "me"
|
local[0] = func.local[0]; // load "me"
|
||||||
|
|
||||||
// load local scope & default arguments
|
// load local scope & default arguments
|
||||||
for(u64 i = min_size+1; i<func.local_size; ++i) {
|
for(u64 i = min_size + 1; i<func.local_size; ++i) {
|
||||||
local[i] = func.local[i];
|
local[i] = func.local[i];
|
||||||
}
|
}
|
||||||
// load dynamic argument
|
|
||||||
local[func.dynamic_parameter_index>=0?
|
|
||||||
parameter_size+1:func.local_size-1] = dynamic;
|
|
||||||
|
|
||||||
ctx.top[0] = ctx.upvalr;
|
// load dynamic argument
|
||||||
(++ctx.top)[0] = var::addr(ctx.localr);
|
local[func.dynamic_parameter_index >= 0
|
||||||
(++ctx.top)[0] = var::ret(ctx.pc);
|
? parameter_size + 1
|
||||||
ctx.pc = func.entry-1;
|
: func.local_size - 1] = dynamic;
|
||||||
ctx.localr = local;
|
|
||||||
ctx.upvalr = nil;
|
set_frame(func, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_callfh() {
|
inline void vm::o_callfh() {
|
||||||
const auto& hash = ctx.top[0].hash().elems;
|
const auto& hash = ctx.top[0].hash().elems;
|
||||||
if (!ctx.top[-1].is_func()) {
|
if (!ctx.top[-1].is_func()) {
|
||||||
die("must call a function but get "+type_name_string(ctx.top[-1]));
|
die("must call a function but get " + type_name_string(ctx.top[-1]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto& func = ctx.top[-1].func();
|
const auto& func = ctx.top[-1].func();
|
||||||
|
@ -983,12 +998,7 @@ inline void vm::o_callfh() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.top[0] = ctx.upvalr;
|
set_frame(func, local);
|
||||||
(++ctx.top)[0] = var::addr(ctx.localr);
|
|
||||||
(++ctx.top)[0] = var::ret(ctx.pc); // rewrite top with vm_ret
|
|
||||||
ctx.pc=func.entry-1;
|
|
||||||
ctx.localr = local;
|
|
||||||
ctx.upvalr = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vm::o_callb() {
|
inline void vm::o_callb() {
|
||||||
|
@ -1020,7 +1030,7 @@ inline void vm::o_slcbeg() {
|
||||||
// +--------------+
|
// +--------------+
|
||||||
(++ctx.top)[0] = ngc.alloc(vm_type::vm_vec);
|
(++ctx.top)[0] = ngc.alloc(vm_type::vm_vec);
|
||||||
if (!ctx.top[-1].is_vec()) {
|
if (!ctx.top[-1].is_vec()) {
|
||||||
die("must slice a vector but get "+type_name_string(ctx.top[-1]));
|
die("must slice a vector but get " + type_name_string(ctx.top[-1]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1090,8 +1100,8 @@ inline void vm::o_mcalll() {
|
||||||
inline void vm::o_mupval() {
|
inline void vm::o_mupval() {
|
||||||
ctx.memr = &(
|
ctx.memr = &(
|
||||||
ctx.funcr.func()
|
ctx.funcr.func()
|
||||||
.upval[(imm[ctx.pc]>>16)&0xffff]
|
.upval[(imm[ctx.pc]>>16) & 0xffff]
|
||||||
.upval()[imm[ctx.pc]&0xffff]
|
.upval()[imm[ctx.pc] & 0xffff]
|
||||||
);
|
);
|
||||||
(++ctx.top)[0] = ctx.memr[0];
|
(++ctx.top)[0] = ctx.memr[0];
|
||||||
// push value in this memory space on stack
|
// push value in this memory space on stack
|
||||||
|
@ -1109,7 +1119,7 @@ inline void vm::o_mcallv() {
|
||||||
}
|
}
|
||||||
} else if (vec.is_hash()) { // do mcallh but use the mcallv way
|
} else if (vec.is_hash()) { // do mcallh but use the mcallv way
|
||||||
if (!val.is_str()) {
|
if (!val.is_str()) {
|
||||||
die("must use string as the key but get "+type_name_string(val));
|
die("must use string as the key but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& ref = vec.hash();
|
auto& ref = vec.hash();
|
||||||
|
@ -1121,7 +1131,7 @@ inline void vm::o_mcallv() {
|
||||||
}
|
}
|
||||||
} else if (vec.is_map()) {
|
} else if (vec.is_map()) {
|
||||||
if (!val.is_str()) {
|
if (!val.is_str()) {
|
||||||
die("must use string as the key but get "+type_name_string(val));
|
die("must use string as the key but get " + type_name_string(val));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& ref = vec.map();
|
auto& ref = vec.map();
|
||||||
|
@ -1199,7 +1209,7 @@ inline void vm::o_ret() {
|
||||||
auto size = func.func().local_size;
|
auto size = func.func().local_size;
|
||||||
upval.on_stack = false;
|
upval.on_stack = false;
|
||||||
upval.elems.resize(size);
|
upval.elems.resize(size);
|
||||||
for(u64 i = 0; i<size; ++i) {
|
for(u64 i = 0; i < size; ++i) {
|
||||||
upval.elems[i] = local[i];
|
upval.elems[i] = local[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,35 +18,64 @@ void dynamic_library_destructor(void* pointer) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> possible_dylib_path() {
|
||||||
|
const auto env_path = std::string(getenv("PATH"));
|
||||||
|
const auto sep = (util::is_windows()? ";":":");
|
||||||
|
const auto path_front = util::is_windows()? "\\module\\":"/module/";
|
||||||
|
|
||||||
|
// do split string
|
||||||
|
std::vector<std::string> env_path_vec = {"."};
|
||||||
|
usize last = 0;
|
||||||
|
usize pos = env_path.find(sep, 0);
|
||||||
|
while(pos != std::string::npos) {
|
||||||
|
if (pos > last) {
|
||||||
|
env_path_vec.push_back(env_path.substr(last, pos - last));
|
||||||
|
}
|
||||||
|
last = pos + 1;
|
||||||
|
pos = env_path.find(sep, last);
|
||||||
|
}
|
||||||
|
if (last != env_path.length()) {
|
||||||
|
env_path_vec.push_back(env_path.substr(last));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& p : env_path_vec) {
|
||||||
|
p += path_front;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env_path_vec;
|
||||||
|
}
|
||||||
|
|
||||||
std::string search_dynamic_library_path(const std::string& dlname) {
|
std::string search_dynamic_library_path(const std::string& dlname) {
|
||||||
const auto ext = (util::is_windows()? ".dll":".so");
|
const auto ext = (util::is_windows()? ".dll":".so");
|
||||||
const auto lib_path = (util::is_windows()? ".\\":"./") + dlname + ext;
|
const auto lib_path = (util::is_windows()? ".\\":"./") + dlname + ext;
|
||||||
if (fs::exists(lib_path)) {
|
if (fs::exists(lib_path)) {
|
||||||
return lib_path;
|
return lib_path;
|
||||||
}
|
}
|
||||||
const auto env_path = std::string(getenv("PATH"));
|
// macos may use .dylib as extension
|
||||||
const auto sep = (util::is_windows()? ";":":");
|
if (util::is_macos()) {
|
||||||
|
const auto dylib_path = "./" + dlname + ".dylib";
|
||||||
// do split string
|
if (fs::exists(dylib_path)) {
|
||||||
std::vector<std::string> env_path_vec = {"."};
|
return dylib_path;
|
||||||
usize last = 0;
|
|
||||||
usize pos = env_path.find(sep, 0);
|
|
||||||
while(pos!=std::string::npos) {
|
|
||||||
if (pos>last) {
|
|
||||||
env_path_vec.push_back(env_path.substr(last, pos-last));
|
|
||||||
}
|
}
|
||||||
last = pos + 1;
|
|
||||||
pos = env_path.find(sep, last);
|
|
||||||
}
|
|
||||||
if (last!=env_path.length()) {
|
|
||||||
env_path_vec.push_back(env_path.substr(last));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto path_front = util::is_windows()? "\\module\\":"/module/";
|
// search library in PATH
|
||||||
for(auto& p : env_path_vec) {
|
const auto possible_path = possible_dylib_path();
|
||||||
p += path_front + lib_path;
|
for(const auto& p : possible_path) {
|
||||||
if (fs::exists(p)) {
|
const auto env_p = p + lib_path;
|
||||||
return p;
|
if (fs::exists(env_p)) {
|
||||||
|
return env_p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// macos may use .dylib as extension
|
||||||
|
if (util::is_macos()) {
|
||||||
|
const auto dylib_path = "./" + dlname + ".dylib";
|
||||||
|
for(const auto& p : possible_path) {
|
||||||
|
const auto env_p = p + dylib_path;
|
||||||
|
if (fs::exists(env_p)) {
|
||||||
|
return env_p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
@ -61,7 +90,7 @@ var builtin_dlopen(context* ctx, gc* ngc) {
|
||||||
const auto dlname = search_dynamic_library_path(dl.str());
|
const auto dlname = search_dynamic_library_path(dl.str());
|
||||||
if (dlname.empty()) {
|
if (dlname.empty()) {
|
||||||
return nas_err("dylib::dlopen",
|
return nas_err("dylib::dlopen",
|
||||||
"cannot find dynamic lib <" + dl.str() + ">"
|
"cannot find dynamic library <" + dl.str() + ">"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,13 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
void dynamic_library_destructor(void*);
|
void dynamic_library_destructor(void*);
|
||||||
|
|
||||||
|
std::vector<std::string> possible_dylib_path();
|
||||||
std::string search_dynamic_library_path(const std::string&);
|
std::string search_dynamic_library_path(const std::string&);
|
||||||
|
|
||||||
var builtin_dlopen(context*, gc*);
|
var builtin_dlopen(context*, gc*);
|
||||||
|
|
|
@ -44,7 +44,7 @@ void optimizer::const_number(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
node->set_optimized_number(
|
node->set_optimized_number(
|
||||||
new number_literal(node->get_location(), res)
|
new number_literal(node->get_location(), res, "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ void optimizer::const_number(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
node->set_optimized_number(
|
node->set_optimized_number(
|
||||||
new number_literal(node->get_location(), res)
|
new number_literal(node->get_location(), res, "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,7 @@ var _parse = func(parser, args, result_hash) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _add_command = func(parser, long, short, help, need_arg , need_nargs) {
|
var _add_command = func(parser, long, short, help, need_arg, need_nargs) {
|
||||||
var new_command = {
|
var new_command = {
|
||||||
full_name: long,
|
full_name: long,
|
||||||
short_name: short,
|
short_name: short,
|
||||||
|
|
10
std/csv.nas
10
std/csv.nas
|
@ -2,14 +2,14 @@
|
||||||
# ValKmjolnir 2022/10/15
|
# ValKmjolnir 2022/10/15
|
||||||
use std.io;
|
use std.io;
|
||||||
|
|
||||||
var read = func(path, delimeter=",", endline="\n") {
|
var read = func(path, delimeter = ",", endline = "\n") {
|
||||||
var context = io.readfile(path);
|
var context = io.readfile(path);
|
||||||
context = split(endline, context);
|
context = split(endline, context);
|
||||||
forindex(var i;context) {
|
forindex(var i; context) {
|
||||||
context[i] = split(delimeter,context[i]);
|
context[i] = split(delimeter, context[i]);
|
||||||
}
|
}
|
||||||
if (size(context)<=1) {
|
if (size(context) <= 1) {
|
||||||
die("incorrect csv file <"~path~">: "~size(context)~" line(s).");
|
die("incorrect csv file <" ~ path ~ ">: " ~ size(context) ~ " line(s).");
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
property: context[0],
|
property: context[0],
|
||||||
|
|
24
std/file.nas
24
std/file.nas
|
@ -4,12 +4,10 @@ use std.io;
|
||||||
use std.unix;
|
use std.unix;
|
||||||
|
|
||||||
var SEEK_SET = io.SEEK_SET;
|
var SEEK_SET = io.SEEK_SET;
|
||||||
|
|
||||||
var SEEK_CUR = io.SEEK_CUR;
|
var SEEK_CUR = io.SEEK_CUR;
|
||||||
|
|
||||||
var SEEK_END = io.SEEK_END;
|
var SEEK_END = io.SEEK_END;
|
||||||
|
|
||||||
var new = func(filename, mode="r") {
|
var new = func(filename, mode = "r") {
|
||||||
if (!io.exists(filename)) {
|
if (!io.exists(filename)) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +54,7 @@ var find_all_files = func(path) {
|
||||||
var dd = unix.opendir(path);
|
var dd = unix.opendir(path);
|
||||||
var res = [];
|
var res = [];
|
||||||
while(var n = unix.readdir(dd)) {
|
while(var n = unix.readdir(dd)) {
|
||||||
if (unix.isfile(path~"/"~n)) {
|
if (unix.isfile(path ~ "/" ~ n)) {
|
||||||
append(res, n);
|
append(res, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,11 +72,11 @@ var recursive_find_files = func(path) {
|
||||||
files: []
|
files: []
|
||||||
};
|
};
|
||||||
while(var n = unix.readdir(dd)) {
|
while(var n = unix.readdir(dd)) {
|
||||||
if (unix.isfile(path~"/"~n)) {
|
if (unix.isfile(path ~ "/" ~ n)) {
|
||||||
append(res.files, n);
|
append(res.files, n);
|
||||||
} elsif (unix.isdir(path~"/"~n) and n!="." and n!="..") {
|
} elsif (unix.isdir(path ~ "/" ~ n) and n != "." and n != "..") {
|
||||||
var tmp = recursive_find_files(path~"/"~n);
|
var tmp = recursive_find_files(path ~ "/" ~ n);
|
||||||
if (tmp!=nil) {
|
if (tmp != nil) {
|
||||||
append(res.files, tmp);
|
append(res.files, tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,19 +87,19 @@ var recursive_find_files = func(path) {
|
||||||
|
|
||||||
var recursive_find_files_flat = func(path) {
|
var recursive_find_files_flat = func(path) {
|
||||||
var tree_files = recursive_find_files(path);
|
var tree_files = recursive_find_files(path);
|
||||||
if (tree_files==nil) {
|
if (tree_files == nil) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var flat = [];
|
var flat = [];
|
||||||
var bfs = [tree_files];
|
var bfs = [tree_files];
|
||||||
while(size(bfs)!=0) {
|
while(size(bfs) != 0) {
|
||||||
var first = pop(bfs);
|
var first = pop(bfs);
|
||||||
foreach(var file_record; first.files) {
|
foreach(var file_record; first.files) {
|
||||||
if (ishash(file_record)) {
|
if (ishash(file_record)) {
|
||||||
append(bfs, file_record);
|
append(bfs, file_record);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
append(flat, first.dir~"/"~file_record);
|
append(flat, first.dir ~ "/" ~ file_record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flat;
|
return flat;
|
||||||
|
@ -110,7 +108,7 @@ var recursive_find_files_flat = func(path) {
|
||||||
var recursive_find_files_with_extension = func(path, extensions...) {
|
var recursive_find_files_with_extension = func(path, extensions...) {
|
||||||
var in_vec = func(ext) {
|
var in_vec = func(ext) {
|
||||||
foreach(var i; extensions) {
|
foreach(var i; extensions) {
|
||||||
if (ext==i) {
|
if (ext == i) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +119,7 @@ var recursive_find_files_with_extension = func(path, extensions...) {
|
||||||
var res = [];
|
var res = [];
|
||||||
foreach(var filename; files) {
|
foreach(var filename; files) {
|
||||||
var tmp = split('.', filename);
|
var tmp = split('.', filename);
|
||||||
if (size(tmp)>1 and in_vec(tmp[-1])) {
|
if (size(tmp) > 1 and in_vec(tmp[-1])) {
|
||||||
append(res, filename);
|
append(res, filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@ var bind = func(function, locals, outer_scope = nil) {
|
||||||
die("this runtime does not support bind");
|
die("this runtime does not support bind");
|
||||||
}
|
}
|
||||||
|
|
||||||
var call = func(function ,args = nil, _me = nil, locals = nil, error = nil) {
|
var call = func(function, args = nil, _me = nil, locals = nil, error = nil) {
|
||||||
die("this runtime does not support call");
|
die("this runtime does not support call");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,32 +4,32 @@ var new = func() {
|
||||||
var (begin, end) = (nil, nil);
|
var (begin, end) = (nil, nil);
|
||||||
return{
|
return{
|
||||||
push: func(elem) {
|
push: func(elem) {
|
||||||
var new_node={
|
var new_node = {
|
||||||
elem:elem,
|
elem:elem,
|
||||||
next:nil
|
next:nil
|
||||||
};
|
};
|
||||||
if (begin==nil)
|
if (begin == nil)
|
||||||
begin=end=new_node;
|
begin = end = new_node;
|
||||||
else {
|
else {
|
||||||
end.next=new_node;
|
end.next = new_node;
|
||||||
end=new_node;
|
end = new_node;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pop: func() {
|
pop: func() {
|
||||||
if (begin!=nil)
|
if (begin != nil)
|
||||||
begin=begin.next;
|
begin = begin.next;
|
||||||
if (begin==nil)
|
if (begin == nil)
|
||||||
end=nil;
|
end = nil;
|
||||||
},
|
},
|
||||||
front: func() {
|
front: func() {
|
||||||
if (begin!=nil)
|
if (begin != nil)
|
||||||
return begin.elem;
|
return begin.elem;
|
||||||
},
|
},
|
||||||
clear: func() {
|
clear: func() {
|
||||||
begin=end=nil;
|
begin = end = nil;
|
||||||
},
|
},
|
||||||
empty: func() {
|
empty: func() {
|
||||||
return begin==nil;
|
return begin == nil;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ var stack = func() {
|
||||||
return pop(vec);
|
return pop(vec);
|
||||||
},
|
},
|
||||||
top: func() {
|
top: func() {
|
||||||
if (size(vec)!=0) {
|
if (size(vec) != 0) {
|
||||||
return vec[-1];
|
return vec[-1];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -18,7 +18,7 @@ var stack = func() {
|
||||||
vec = [];
|
vec = [];
|
||||||
},
|
},
|
||||||
empty: func() {
|
empty: func() {
|
||||||
return size(vec)==0;
|
return size(vec) == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,11 +33,13 @@ func() {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var to_char = func(number) {
|
var to_char = func(number) {
|
||||||
return 0<=number and number<256? __num_to_char[number]:"";
|
return 0 <= number and number < 256? __num_to_char[number] : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var to_num = func(character) {
|
var to_num = func(character) {
|
||||||
return __temp_contains(__char_to_num, character)? __char_to_num[character]:-1;
|
return __temp_contains(__char_to_num, character)
|
||||||
|
? __char_to_num[character]
|
||||||
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var __string_split_with_empty_substr = func(separator, str) {
|
var __string_split_with_empty_substr = func(separator, str) {
|
||||||
|
|
|
@ -16,8 +16,8 @@ var ppm = func(filename, width, height, RGB) {
|
||||||
io.close(fd);
|
io.close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
var width = 1920;
|
var width = 1920 * 2;
|
||||||
var height = 1080;
|
var height = 1080 * 2;
|
||||||
var bar = (os.platform()=="windows")?
|
var bar = (os.platform()=="windows")?
|
||||||
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
||||||
process_bar.high_resolution_bar(50);
|
process_bar.high_resolution_bar(50);
|
||||||
|
|
|
@ -31,7 +31,8 @@ func() {
|
||||||
runtime.gc.extend("vec", 8);
|
runtime.gc.extend("vec", 8);
|
||||||
}();
|
}();
|
||||||
|
|
||||||
var (max,min,sqrt,sin,cos,abs)=(
|
# alias
|
||||||
|
var (max, min, sqrt, sin, cos, abs) = (
|
||||||
math.max,
|
math.max,
|
||||||
math.min,
|
math.min,
|
||||||
math.sqrt,
|
math.sqrt,
|
||||||
|
@ -40,12 +41,12 @@ var (max,min,sqrt,sin,cos,abs)=(
|
||||||
math.abs
|
math.abs
|
||||||
);
|
);
|
||||||
|
|
||||||
var (vec2,vec3)=(
|
var (vec2, vec3) = (
|
||||||
libmat.vec2.new,
|
libmat.vec2.new,
|
||||||
libmat.vec3.new
|
libmat.vec3.new
|
||||||
);
|
);
|
||||||
|
|
||||||
var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=(
|
var (vec2add, vec2sub, vec2mul, vec2div, vec2len) = (
|
||||||
libmat.vec2.add,
|
libmat.vec2.add,
|
||||||
libmat.vec2.sub,
|
libmat.vec2.sub,
|
||||||
libmat.vec2.mul,
|
libmat.vec2.mul,
|
||||||
|
@ -53,7 +54,7 @@ var (vec2add,vec2sub,vec2mul,vec2div,vec2len)=(
|
||||||
libmat.vec2.len
|
libmat.vec2.len
|
||||||
);
|
);
|
||||||
|
|
||||||
var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=(
|
var (vec3add, vec3sub, vec3mul, vec3div, vec3neg, vec3norm, vec3len, vec3dot) = (
|
||||||
libmat.vec3.add,
|
libmat.vec3.add,
|
||||||
libmat.vec3.sub,
|
libmat.vec3.sub,
|
||||||
libmat.vec3.mul,
|
libmat.vec3.mul,
|
||||||
|
@ -64,116 +65,147 @@ var (vec3add,vec3sub,vec3mul,vec3div,vec3neg,vec3norm,vec3len,vec3dot)=(
|
||||||
libmat.vec3.dot
|
libmat.vec3.dot
|
||||||
);
|
);
|
||||||
|
|
||||||
var (rotateX,rotateY,rotateZ)=(
|
var (rotateX, rotateY, rotateZ) = (
|
||||||
libmat.vec3.rx,
|
libmat.vec3.rx,
|
||||||
libmat.vec3.ry,
|
libmat.vec3.ry,
|
||||||
libmat.vec3.rz,
|
libmat.vec3.rz,
|
||||||
);
|
);
|
||||||
|
|
||||||
var use_raw = func() {
|
var use_raw = func() {
|
||||||
vec2 = func(x,y) {return [x,y];}
|
vec2 = func(x, y) {return [x,y];}
|
||||||
vec2add = func(v1,v2) {return [v1[0]+v2[0],v1[1]+v2[1]];}
|
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]];}
|
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]];}
|
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]];}
|
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);}
|
vec2len = func(v) {var (x,y)=(v[0],v[1]); return sqrt(x*x+y*y);}
|
||||||
|
|
||||||
|
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]];}
|
||||||
vec3len = func(v) {var (x,y,z)=(v[0],v[1],v[2]); return sqrt(x*x+y*y+z*z);}
|
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]);}
|
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];}
|
vec3dot = func(a, b) {
|
||||||
rotateX = func(a,angle) {return [a[0],a[2]*sin(angle)+a[1]*cos(angle),a[2]*cos(angle)-a[1]*sin(angle)];}
|
return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
|
||||||
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]];}
|
|
||||||
|
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) {
|
var clamp = func(value, _min, _max) {
|
||||||
return max(min(value,_max),_min);
|
return max(min(value, _max), _min);
|
||||||
}
|
}
|
||||||
var sign = func(a) {
|
var sign = func(a) {
|
||||||
return (0<a)-(a<0);
|
return (0 < a) - (a < 0);
|
||||||
}
|
}
|
||||||
var step = func(edge,x) {
|
var step = func(edge, x) {
|
||||||
return x>edge;
|
return x > edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vec3abs = func(v) {
|
var vec3abs = func(v) {
|
||||||
return [abs(v[0]),abs(v[1]),abs(v[2])];
|
return [abs(v[0]), abs(v[1]), abs(v[2])];
|
||||||
}
|
}
|
||||||
var vec3sign = func(v) {
|
var vec3sign = func(v) {
|
||||||
return [sign(v[0]),sign(v[1]),sign(v[2])];
|
return [sign(v[0]), sign(v[1]), sign(v[2])];
|
||||||
}
|
}
|
||||||
var vec3step = func(edge,v) {
|
var vec3step = func(edge, v) {
|
||||||
return [step(edge[0],v[0]),step(edge[1],v[1]),step(edge[2],v[2])];
|
return [
|
||||||
|
step(edge[0], v[0]),
|
||||||
|
step(edge[1], v[1]),
|
||||||
|
step(edge[2], v[2])
|
||||||
|
];
|
||||||
}
|
}
|
||||||
var vec3reflect = func(rd,n) {
|
var vec3reflect = func(rd, n) {
|
||||||
var d=vec3dot(n,rd);
|
var d = vec3dot(n, rd);
|
||||||
return vec3sub(rd,vec3mul(n,vec3mul([2,2,2],[d,d,d])));
|
return vec3sub(rd, vec3mul(n, vec3mul([2, 2, 2], [d, d, d])));
|
||||||
}
|
}
|
||||||
|
|
||||||
var sphere = func(ro,rd,r) {
|
var sphere = func(ro, rd, r) {
|
||||||
var b=vec3dot(ro,rd);
|
var b = vec3dot(ro, rd);
|
||||||
var c=vec3dot(ro,ro)-r*r;
|
var c = vec3dot(ro, ro) - r * r;
|
||||||
var h=b*b-c;
|
var h = b * b - c;
|
||||||
if (h<0.0) return [-1.0,-1.0];
|
if (h < 0.0)
|
||||||
h=sqrt(h);
|
return [-1.0, -1.0];
|
||||||
return [-b-h,-b+h];
|
h = sqrt(h);
|
||||||
|
return [-b - h, -b + h];
|
||||||
}
|
}
|
||||||
|
|
||||||
var box = func(ro,rd,boxSize,outNormal) {
|
var box = func(ro, rd, boxSize, outNormal) {
|
||||||
var m=vec3div([1.0,1.0,1.0],rd);
|
var m = vec3div([1.0, 1.0, 1.0], rd);
|
||||||
var n=vec3mul(m,ro);
|
var n = vec3mul(m, ro);
|
||||||
var k=vec3mul(vec3abs(m),boxSize);
|
var k = vec3mul(vec3abs(m), boxSize);
|
||||||
var t1=vec3sub(vec3neg(n),k);
|
var t1 = vec3sub(vec3neg(n), k);
|
||||||
var t2=vec3add(vec3neg(n),k);
|
var t2 = vec3add(vec3neg(n), k);
|
||||||
var tN=max(max(t1[0],t1[1]),t1[2]);
|
var tN = max(max(t1[0], t1[1]), t1[2]);
|
||||||
var tF=min(min(t2[0],t2[1]),t2[2]);
|
var tF = min(min(t2[0], t2[1]), t2[2]);
|
||||||
if (tN>tF or tF<0.0) return [-1.0,-1.0];
|
if (tN>tF or tF<0.0)
|
||||||
var yzx=[t1[1],t1[2],t1[0]];
|
return [-1.0, -1.0];
|
||||||
var zxy=[t1[2],t1[0],t1[1]];
|
var yzx = [t1[1], t1[2], t1[0]];
|
||||||
var tmp=vec3mul(vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx,t1)),vec3step(zxy,t1));
|
var zxy = [t1[2], t1[0], t1[1]];
|
||||||
outNormal[0]=tmp[0];
|
var tmp = vec3mul(
|
||||||
outNormal[1]=tmp[1];
|
vec3mul(vec3neg(vec3sign(rd)), vec3step(yzx, t1)),
|
||||||
outNormal[2]=tmp[2];
|
vec3step(zxy, t1)
|
||||||
|
);
|
||||||
|
outNormal[0] = tmp[0];
|
||||||
|
outNormal[1] = tmp[1];
|
||||||
|
outNormal[2] = tmp[2];
|
||||||
return [tN, tF];
|
return [tN, tF];
|
||||||
}
|
}
|
||||||
|
|
||||||
var plane = func(ro,rd,p,w) {
|
var plane = func(ro, rd, p, w) {
|
||||||
return -(vec3dot(ro,p)+w)/vec3dot(rd,p);
|
return -(vec3dot(ro, p) + w) / vec3dot(rd, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
var main = func(frame) {
|
var main = func(frame) {
|
||||||
|
|
||||||
var height=15*2;
|
var height = 15*2;
|
||||||
var width=int(height*1/0.618)*2;
|
var width = int(height*1/0.618)*2;
|
||||||
|
|
||||||
var aspect=width/height;
|
var aspect = width/height;
|
||||||
var pixelAspect=11.0/24.0;
|
var pixelAspect = 11.0/24.0;
|
||||||
|
|
||||||
var gradient=split(""," .:!/r(l1Z4H9W8$");
|
var gradient = split("", " .:!/r(l1Z4H9W8$");
|
||||||
var gradientSize=size(gradient)-1;
|
var gradientSize = size(gradient)-1;
|
||||||
|
|
||||||
var screen=[];
|
var screen = [];
|
||||||
setsize(screen,width*height);
|
setsize(screen, width*height);
|
||||||
|
|
||||||
var light=vec3norm([-0.5,0.5,-1.0]);
|
var light = vec3norm([-0.5, 0.5, -1.0]);
|
||||||
var spherePos=[0,3,0];
|
var spherePos = [0, 3, 0];
|
||||||
var vec2_2_2=[2,2];
|
var vec2_2_2 = [2, 2];
|
||||||
var vec2_1_1=[1,1];
|
var vec2_1_1 = [1, 1];
|
||||||
var vec3_000=[0,0,0];
|
var vec3_000 = [0, 0, 0];
|
||||||
var vec3_00n1=[0,0,-1];
|
var vec3_00n1 = [0, 0, -1];
|
||||||
var vec3_111=[1,1,1];
|
var vec3_111 = [1, 1, 1];
|
||||||
|
|
||||||
print("\e[2J");
|
print("\e[2J");
|
||||||
var stamp=maketimestamp();
|
var stamp = maketimestamp();
|
||||||
for(var t=0;t<frame;t+=1) {
|
for(var t = 0; t < frame; t += 1) {
|
||||||
stamp.stamp();
|
stamp.stamp();
|
||||||
for(var i=0;i<width;i+=1) {
|
for(var i = 0; i < width; i += 1) {
|
||||||
for(var j=0;j<height;j+=1) {
|
for(var j = 0; j < height; j += 1) {
|
||||||
var uv=vec2sub(vec2mul(vec2div([i,j],[width,height]),vec2_2_2),vec2_1_1);
|
var uv=vec2sub(vec2mul(vec2div([i,j],[width,height]),vec2_2_2),vec2_1_1);
|
||||||
uv[0]*=aspect*pixelAspect;
|
uv[0]*=aspect*pixelAspect;
|
||||||
var ro=[-6,0,0];
|
var ro=[-6,0,0];
|
||||||
|
@ -229,22 +261,28 @@ var main = func(frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var st=maketimestamp();
|
var st = maketimestamp();
|
||||||
var run=[0,0];
|
var run = [0, 0];
|
||||||
var frame=1e3;
|
var frame = 1e3;
|
||||||
if (size(runtime.argv())!=0) {
|
# reset required frame if given
|
||||||
var n=num(runtime.argv()[0]);
|
if (size(runtime.argv()) != 0) {
|
||||||
|
var n = num(runtime.argv()[0]);
|
||||||
if (!math.isnan(n)) {
|
if (!math.isnan(n)) {
|
||||||
frame=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");
|
st.stamp();
|
||||||
println("test 1: ",run[1]/1000,"s ",frame*1000/run[1]," fps");
|
main(frame);
|
||||||
|
run[0] = st.elapsedMSec();
|
||||||
|
|
||||||
|
# switch used matrix library
|
||||||
|
use_raw();
|
||||||
|
|
||||||
|
st.stamp();
|
||||||
|
main(frame);
|
||||||
|
run[1] = st.elapsedMSec();
|
||||||
|
|
||||||
|
println("total frame: ", frame);
|
||||||
|
println("test [0]: ", run[0]/1000, "s with ", frame*1000/run[0], " fps");
|
||||||
|
println("test [1]: ", run[1]/1000, "s with ", frame*1000/run[1], " fps");
|
|
@ -6,75 +6,77 @@ use std.padding;
|
||||||
use std.os;
|
use std.os;
|
||||||
use std.runtime;
|
use std.runtime;
|
||||||
|
|
||||||
if (os.platform()=="windows") {
|
if (os.platform() == "windows") {
|
||||||
runtime.windows.set_utf8_output();
|
runtime.windows.set_utf8_output();
|
||||||
system("color");
|
system("color");
|
||||||
}
|
}
|
||||||
|
|
||||||
var fib = func() {
|
var fib = func() {
|
||||||
var (a,b)=(1,1);
|
var (a, b) = (1, 1);
|
||||||
coroutine.yield(a);
|
coroutine.yield(a);
|
||||||
coroutine.yield(b);
|
coroutine.yield(b);
|
||||||
while(1) {
|
while(1) {
|
||||||
(a,b)=(b,a+b);
|
(a, b) = (b, a + b);
|
||||||
coroutine.yield(b);
|
coroutine.yield(b);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var co=[coroutine.create(fib),coroutine.create(fib)];
|
var co = [coroutine.create(fib), coroutine.create(fib)];
|
||||||
for(var i=0;i<45;i+=1) {
|
for(var i = 0; i < 45; i += 1) {
|
||||||
var res=[coroutine.resume(co[0]),coroutine.resume(co[1])];
|
var res = [coroutine.resume(co[0]), coroutine.resume(co[1])];
|
||||||
if (res[0]==nil or res[1]==nil or res[0][0]!=res[1][0])
|
if (res[0] == nil or res[1] == nil or res[0][0] != res[1][0])
|
||||||
die("different coroutines don't share the same local scope");
|
die("different coroutines don't share the same local scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
# test if coroutine can get upvalues
|
# test if coroutine can get upvalues
|
||||||
func() {
|
func() {
|
||||||
var x=1;
|
var x = 1;
|
||||||
var co=coroutine.create(func() {
|
var co = coroutine.create(func() {
|
||||||
for(var j=0;j<128;j+=1) {
|
for(var j = 0; j < 128; j += 1) {
|
||||||
coroutine.yield(x,i,j);
|
coroutine.yield(x, i, j);
|
||||||
x+=1;
|
x += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for(var i=0;i<16;i+=1) {
|
for(var i = 0; i < 16; i += 1) {
|
||||||
var res=coroutine.resume(co);
|
var res = coroutine.resume(co);
|
||||||
if (res==nil or res[0]!=x or res[1]!=i)
|
if (res == nil or res[0] != x or res[1] != i)
|
||||||
die("coroutine should have the ability to get upvalues");
|
die("coroutine should have the ability to get upvalues");
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
# test coroutine.resume passing arguments to coroutine
|
# test coroutine.resume passing arguments to coroutine
|
||||||
func {
|
func {
|
||||||
var co=coroutine.create(func() {
|
var co = coroutine.create(func() {
|
||||||
var (a,b)=coroutine.yield(a+b);
|
var (a, b) = coroutine.yield(a + b);
|
||||||
println("coroutine.yield get ",a," ",b);
|
println("[0] coroutine.yield get ", a, " ", b);
|
||||||
(a,b)=coroutine.yield(a+b);
|
(a, b) = coroutine.yield(a + b);
|
||||||
println("coroutine.yield get ",a," ",b);
|
println("[0] coroutine.yield get ", a, " ", b);
|
||||||
return "end";
|
return "end";
|
||||||
});
|
});
|
||||||
|
|
||||||
for(var i=0;i<5;i+=1)
|
for(var i = 0; i < 5; i += 1)
|
||||||
println("coroutine.resume get ",coroutine.resume(co,i,i+1));
|
println("[0] coroutine.resume get ", coroutine.resume(co, i, i + 1));
|
||||||
|
print("\n");
|
||||||
}();
|
}();
|
||||||
|
|
||||||
# test crash in coroutines
|
# test crash in coroutines
|
||||||
var co=coroutine.create(func {
|
var co = coroutine.create(func {
|
||||||
var b = func() {b()}
|
var b = func() { b() }
|
||||||
coroutine.yield(b);
|
coroutine.yield(b);
|
||||||
b();
|
b();
|
||||||
coroutine.yield(0);
|
coroutine.yield(0); # unreachable
|
||||||
});
|
});
|
||||||
|
|
||||||
println("coroutine yield: ",coroutine.resume(co));
|
println("[1] coroutine yield: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
|
println("[1] coroutine state after yield:\e[32m ", coroutine.status(co), "\e[0m");
|
||||||
println("coroutine error: ",coroutine.resume(co));
|
println("[1] coroutine stackoverflow error: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
println("[1] coroutine state after error:\e[91m ", coroutine.status(co), "\e[0m");
|
||||||
println("coroutine yield: ",coroutine.resume(co));
|
println("[1] coroutine yield after error: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
println("[1] coroutine state after error:\e[91m ", coroutine.status(co), "\e[0m");
|
||||||
|
print("\n");
|
||||||
|
|
||||||
var co = coroutine.create(func {
|
var co = coroutine.create(func {
|
||||||
var a=1;
|
var a = 1;
|
||||||
var b = func() {
|
var b = func() {
|
||||||
b();
|
b();
|
||||||
}
|
}
|
||||||
|
@ -82,44 +84,46 @@ var co = coroutine.create(func {
|
||||||
coroutine.yield(b());
|
coroutine.yield(b());
|
||||||
});
|
});
|
||||||
|
|
||||||
println("coroutine yield: ",coroutine.resume(co));
|
println("[2] coroutine yield: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[32m ",coroutine.status(co),"\e[0m");
|
println("[2] coroutine state:\e[32m ", coroutine.status(co), "\e[0m");
|
||||||
println("coroutine error: ",coroutine.resume(co));
|
println("[2] coroutine error: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
println("[2] coroutine state:\e[91m ", coroutine.status(co), "\e[0m");
|
||||||
println("coroutine yield: ",coroutine.resume(co));
|
println("[2] coroutine yield: ", coroutine.resume(co));
|
||||||
println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
println("[2] coroutine state:\e[91m ", coroutine.status(co), "\e[0m");
|
||||||
println("ok");
|
println("[2] ok\n");
|
||||||
|
|
||||||
# pressure test
|
# pressure test
|
||||||
for(var t=0;t<10;t+=1) {
|
for(var t = 0; t < 10; t += 1) {
|
||||||
var productor = func() {
|
var productor = func() {
|
||||||
while(1) {
|
while(1) {
|
||||||
coroutine.yield(i);
|
coroutine.yield(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var co=coroutine.create(productor);
|
var co = coroutine.create(productor);
|
||||||
var tm=maketimestamp();
|
var tm = maketimestamp();
|
||||||
|
|
||||||
var counter=0;
|
var counter = 0;
|
||||||
var bar=process_bar.high_resolution_bar(40);
|
var bar = process_bar.high_resolution_bar(40);
|
||||||
var consumer = func() {
|
var consumer = func() {
|
||||||
counter+=1;
|
counter += 1;
|
||||||
for(var i=0;i<t+1;i+=1)
|
for(var i = 0; i < t + 1; i += 1)
|
||||||
coroutine.resume(co);
|
coroutine.resume(co);
|
||||||
if (counter-int(counter/1000)*1000==0) {
|
if (counter - int(counter / 1000) * 1000 == 0) {
|
||||||
var rate=counter/2e5;
|
var rate = counter / 2e5;
|
||||||
print(" ",bar.bar(rate)," ",
|
print(" ", bar.bar(rate), " ",
|
||||||
padding.leftpad(str(int(rate*100)),3),"% | ",
|
padding.leftpad(str(int(rate*100)),3), "% | ",
|
||||||
str(1e3*int(counter/tm.elapsedMSec())),
|
str(1e3 * int(counter / tm.elapsedMSec())),
|
||||||
" tasks/s \r");
|
" tasks/s \r"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tm.stamp();
|
tm.stamp();
|
||||||
for(var i=0;i<1e5;i+=1)
|
for(var i = 0; i < 1e5; i += 1)
|
||||||
consumer();
|
consumer();
|
||||||
println(" ",bar.bar(1)," 100% | ",
|
println(" ", bar.bar(1), " 100% | ",
|
||||||
str(int(1e3*counter/tm.elapsedMSec())),
|
str(int(1e3 * counter / tm.elapsedMSec())),
|
||||||
" tasks/s ");
|
" tasks/s "
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -16,25 +16,29 @@ var ppm = func(filename, width, height, RGB) {
|
||||||
io.close(fd);
|
io.close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
var width = 1920;
|
var width = 1920 * 2;
|
||||||
var height = 1080;
|
var height = 1080 * 2;
|
||||||
var bar = (os.platform()=="windows")?
|
var bar = (os.platform()=="windows")?
|
||||||
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
||||||
process_bar.high_resolution_bar(50);
|
process_bar.high_resolution_bar(50);
|
||||||
|
var abs = math.abs; # alias
|
||||||
|
|
||||||
var RGB = func(h, w) {
|
var RGB = func(h, w) {
|
||||||
var r = 2+w*2/width;
|
var r = 2+w*2/width;
|
||||||
var x = (height-h)/height;
|
var x = (height-h)/height;
|
||||||
|
|
||||||
var res = 0;
|
var (R, G, B) = (0, 0, 0);
|
||||||
|
|
||||||
var tmp = 0.5;
|
var tmp = 0.5;
|
||||||
for(var i = 0; i<50; i+=1) {
|
for(var i = 0; i<50; i+=1) {
|
||||||
tmp = r*tmp*(1-tmp);
|
tmp = r*tmp*(1-tmp);
|
||||||
}
|
}
|
||||||
for(var i = 0; i<100; i+=1) {
|
for(var i = 0; i<150; i+=1) {
|
||||||
tmp = r*tmp*(1-tmp);
|
tmp = r*tmp*(1-tmp);
|
||||||
if (math.abs(tmp-x)<0.001) {
|
if (abs(tmp-x)<0.0005) {
|
||||||
res = 255;
|
R = int(255*(150 - i)/150);
|
||||||
|
G = int(255*(150 - i)/150);
|
||||||
|
B = 255;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,8 +48,7 @@ var RGB = func(h, w) {
|
||||||
print(bar.bar(progress), " ", progress*100, "% \r");
|
print(bar.bar(progress), " ", progress*100, "% \r");
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = char(res);
|
return char(R) ~ char(G) ~ char(B);
|
||||||
return c~c~c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ppm("feigenbaum.ppm", width, height, RGB);
|
ppm("feigenbaum.ppm", width, height, RGB);
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
|
var (yMin, yMax, xMin, xMax, line) = (-0.2, 0.2, -1.5, -1.0, "");
|
||||||
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
|
var (yDel, xDel) = (yMax-yMin, xMax-xMin);
|
||||||
for(var yPixel=0;yPixel<24;yPixel+=1) {
|
for(var yPixel = 0; yPixel < 24; yPixel += 1) {
|
||||||
var y=(yPixel/24)*yDel+yMin;
|
var y = (yPixel/24)*yDel+yMin;
|
||||||
for(var xPixel=0;xPixel<80;xPixel+=1) {
|
for(var xPixel = 0; xPixel < 80; xPixel += 1) {
|
||||||
var x=(xPixel/80)*xDel+xMin;
|
var x = (xPixel/80)*xDel+xMin;
|
||||||
var pixel=" ";
|
var pixel = " ";
|
||||||
var (x0,y0)=(x,y);
|
var (x0, y0) = (x, y);
|
||||||
for(var iter=0;iter<80;iter+=1) {
|
for(var iter = 0; iter < 100; iter += 1) {
|
||||||
var x1=(x0*x0)-(y0*y0)+x;
|
var x1 = (x0*x0)-(y0*y0)+x;
|
||||||
var y1=2*x0*y0+y;
|
var y1 = 2*x0*y0+y;
|
||||||
(x0,y0)=(x1,y1);
|
(x0, y0) = (x1, y1);
|
||||||
if ((x0*x0)+(y0*y0)>4) {
|
if ((x0*x0)+(y0*y0)>4) {
|
||||||
pixel=chr(" .:;+=xX$&"[iter/8]);
|
pixel = chr(" .:;+=xX$&"[iter/8]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
line~=pixel;
|
line ~= pixel;
|
||||||
}
|
}
|
||||||
line~='\n';
|
line ~= '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
print(line);
|
print(line);
|
|
@ -15,8 +15,8 @@ var ppm = func(filename, width, height, RGB) {
|
||||||
io.close(fd);
|
io.close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
var width = 1920;
|
var width = 1920 * 2;
|
||||||
var height = 1080;
|
var height = 1080 * 2;
|
||||||
var bar = (os.platform()=="windows")?
|
var bar = (os.platform()=="windows")?
|
||||||
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
process_bar.bar(front:"sharp", back:"point", sep:"line", length:50):
|
||||||
process_bar.high_resolution_bar(50);
|
process_bar.high_resolution_bar(50);
|
||||||
|
|
|
@ -10,10 +10,14 @@ if not os.path.exists(build_directory):
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
nasal_executable = pathlib.Path("nasal")
|
nasal_executable = pathlib.Path("nasal")
|
||||||
|
nasal_format_executable = pathlib.Path("nasal-format")
|
||||||
nasal_standard_library = pathlib.Path("std")
|
nasal_standard_library = pathlib.Path("std")
|
||||||
if not os.path.exists(nasal_executable):
|
if not os.path.exists(nasal_executable):
|
||||||
print("pack binaries failed: nasal executable not found")
|
print("pack binaries failed: nasal executable not found")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
if not os.path.exists(nasal_format_executable):
|
||||||
|
print("pack binaries failed: nasal-format executable not found")
|
||||||
|
exit(-1)
|
||||||
if not os.path.exists(nasal_standard_library):
|
if not os.path.exists(nasal_standard_library):
|
||||||
print("pack binaries failed: nasal standard library not found")
|
print("pack binaries failed: nasal standard library not found")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
@ -26,8 +30,12 @@ if not os.path.exists(nasal_module_directory):
|
||||||
dynamic_library_suffix = ""
|
dynamic_library_suffix = ""
|
||||||
if platform.system()=="Windows":
|
if platform.system()=="Windows":
|
||||||
dynamic_library_suffix = ".dll"
|
dynamic_library_suffix = ".dll"
|
||||||
else:
|
elif platform.system()=="Linux":
|
||||||
dynamic_library_suffix = ".so"
|
dynamic_library_suffix = ".so"
|
||||||
|
elif platform.system()=="Darwin":
|
||||||
|
dynamic_library_suffix = ".dylib"
|
||||||
|
else:
|
||||||
|
print("pack binaries failed: unsupported platform")
|
||||||
|
|
||||||
nasal_modules = []
|
nasal_modules = []
|
||||||
for m in ["libfib", "libkey", "libmat", "libnasock"]:
|
for m in ["libfib", "libkey", "libmat", "libnasock"]:
|
||||||
|
@ -43,7 +51,15 @@ for m in ["libfib", "libkey", "libmat", "libnasock"]:
|
||||||
nasal_modules.append(lib)
|
nasal_modules.append(lib)
|
||||||
|
|
||||||
|
|
||||||
tar_file_name = "nasal-{}".format(platform.system())
|
tar_file_name = "nasal"
|
||||||
|
if platform.system()=="Windows":
|
||||||
|
tar_file_name += "-windows-x86_64"
|
||||||
|
elif platform.system()=="Linux":
|
||||||
|
tar_file_name += "-linux-x86_64"
|
||||||
|
elif platform.system()=="Darwin":
|
||||||
|
tar_file_name += "-macos-aarch64"
|
||||||
|
else:
|
||||||
|
print("pack binaries failed: unsupported platform")
|
||||||
|
|
||||||
# create package directory in build directory and copy files needed
|
# create package directory in build directory and copy files needed
|
||||||
package_directory = build_directory.joinpath(tar_file_name)
|
package_directory = build_directory.joinpath(tar_file_name)
|
||||||
|
@ -53,6 +69,7 @@ if not os.path.exists(package_directory):
|
||||||
|
|
||||||
print("pack nasal executable")
|
print("pack nasal executable")
|
||||||
shutil.copy(nasal_executable, package_directory.joinpath(nasal_executable))
|
shutil.copy(nasal_executable, package_directory.joinpath(nasal_executable))
|
||||||
|
shutil.copy(nasal_format_executable, package_directory.joinpath(nasal_format_executable))
|
||||||
|
|
||||||
print("pack nasal standard library")
|
print("pack nasal standard library")
|
||||||
shutil.copytree(nasal_standard_library, package_directory.joinpath(nasal_standard_library))
|
shutil.copytree(nasal_standard_library, package_directory.joinpath(nasal_standard_library))
|
||||||
|
|
Loading…
Reference in New Issue