mirror of
https://github.com/ValKmjolnir/Nasal-Interpreter.git
synced 2026-05-02 02:40:47 +08:00
@@ -41,10 +41,10 @@ set(NASAL_OBJECT_SOURCE_FILE
|
||||
${CMAKE_SOURCE_DIR}/src/util/fs.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/util/gc_stat.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/util/util.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/nasal_ast.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ast/ast_dumper.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ast/ast_format.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ast/ast_visitor.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/ast/ast.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_codegen.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_dbg.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/nasal_err.cpp
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml)
|
||||

|
||||
|
||||
> This document is also available in: [__中文__](./doc/README_zh.md) | [__English__](./README.md)
|
||||
> This document is also available in: [__中文__](./README_zh.md) | [__English__](./README.md)
|
||||
|
||||
## __Contents__
|
||||
|
||||
@@ -453,6 +453,7 @@ Nasal REPL interpreter version 11.1 (Nov 1 2023 23:37:30)
|
||||
A web-based interface is now available for trying out Nasal code directly in your browser. It includes both a code editor and an interactive REPL (WIP).
|
||||
|
||||
### Web Code Editor
|
||||
|
||||
- Syntax highlighting using CodeMirror
|
||||
- Error highlighting and formatting
|
||||
- Example programs
|
||||
@@ -461,7 +462,7 @@ A web-based interface is now available for trying out Nasal code directly in you
|
||||
- Notice: The security of the online interpreter is not well tested, please use it with sandbox mechanism or other security measures.
|
||||
|
||||
### Web REPL
|
||||
- ** IMPORTANT: The time limit in REPL is not correctly implemented yet. Thus this REPL web binding is not considered finished. Do not use it in production before it's fixed. **
|
||||
|
||||
- Interactive command-line style interface in browser
|
||||
- Multi-line input support with proper prompts (`>>>` and `...`)
|
||||
- Command history navigation
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# <img src="./svg/nasal_transparent.svg" height="40px"/> __Nasal - Modern Interpreter__
|
||||
# <img src="doc/svg/nasal_transparent.svg" height="40px"/> __Nasal - Modern Interpreter__
|
||||
|
||||
<img src="../doc/pic/header.png" style="width:600px"></img>
|
||||
<img src="doc/pic/header.png" style="width:600px"></img>
|
||||
|
||||

|
||||
[](../LICENSE)
|
||||

|
||||
[](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/c-cpp.yml)
|
||||
[](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml)
|
||||

|
||||
|
||||
> 这篇文档包含多语言版本: [__中文__](../doc/README_zh.md) | [__English__](../README.md)
|
||||
> 这篇文档包含多语言版本: [__中文__](./README_zh.md) | [__English__](./README.md)
|
||||
|
||||
## __目录__
|
||||
|
||||
@@ -16,10 +17,10 @@
|
||||
* [__下载__](#下载)
|
||||
* [__编译__](#编译)
|
||||
* [__使用方法__](#使用方法)
|
||||
* [__教程__](../doc/tutorial_zh.md)
|
||||
* [__发行日志__](../doc/dev_zh.md#发行日志)
|
||||
* [__开发历史__](../doc/dev_zh.md)
|
||||
* [__测试数据__](../doc/benchmark.md)
|
||||
* [__教程__](doc/tutorial_zh.md)
|
||||
* [__发行日志__](doc/dev_zh.md#发行日志)
|
||||
* [__开发历史__](doc/dev_zh.md)
|
||||
* [__测试数据__](doc/benchmark.md)
|
||||
* [__特殊之处__](#与andy解释器的不同之处)
|
||||
* [__堆栈追踪信息__](#堆栈追踪信息)
|
||||
* [__调试器__](#调试器)
|
||||
@@ -96,7 +97,7 @@ Windows 平台的预览版解释器现在还没配置相关流水线,
|
||||
|
||||
## __使用方法__
|
||||
|
||||

|
||||

|
||||
|
||||
如果你是 `Windows` 用户且想正常输出 unicode,可以这样开启 unicode 代码页:
|
||||
|
||||
@@ -116,7 +117,7 @@ runtime.windows.set_utf8_output();
|
||||
|
||||
## __与andy解释器的不同之处__
|
||||
|
||||

|
||||

|
||||
|
||||
<details><summary>必须用 var 定义变量</summary>
|
||||
|
||||
@@ -151,7 +152,7 @@ code: undefined symbol "i"
|
||||
|
||||
## __堆栈追踪信息__
|
||||
|
||||

|
||||

|
||||
|
||||
当解释器崩溃时,它会反馈错误产生过程的堆栈追踪信息:
|
||||
|
||||
@@ -316,7 +317,7 @@ local (0x55dcb5b43190 <+7>)
|
||||
|
||||
## __调试器__
|
||||
|
||||

|
||||

|
||||
|
||||
在`v8.0`版本中我们添加了调试器。
|
||||
使用这个命令`./nasal -dbg xxx.nas`来启用调试器,接下来调试器会打开文件并输出以下内容:
|
||||
281
makefile
281
makefile
@@ -9,290 +9,10 @@ else
|
||||
CXXFLAGS = -std=$(STD) -c -O3 -fPIC -I src
|
||||
endif
|
||||
|
||||
NASAL_HEADER = \
|
||||
src/ast_dumper.h\
|
||||
src/ast_visitor.h\
|
||||
src/nasal_ast.h\
|
||||
src/natives/builtin.h\
|
||||
src/nasal_codegen.h\
|
||||
src/nasal_dbg.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_gc.h\
|
||||
src/nasal_import.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_opcode.h\
|
||||
src/nasal_parse.h\
|
||||
src/nasal_vm.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal.h\
|
||||
src/optimizer.h\
|
||||
src/symbol_finder.h\
|
||||
src/cli/cli.h\
|
||||
src/natives/fg_props.h\
|
||||
src/natives/bits_lib.h\
|
||||
src/natives/io_lib.h\
|
||||
src/natives/math_lib.h\
|
||||
src/natives/dylib_lib.h\
|
||||
src/natives/json_lib.h\
|
||||
src/natives/unix_lib.h\
|
||||
src/natives/coroutine.h\
|
||||
src/natives/regex_lib.h\
|
||||
src/natives/subprocess.h\
|
||||
src/repl/repl.h\
|
||||
src/util/fs.h\
|
||||
src/util/util.h
|
||||
|
||||
NASAL_OBJECT = \
|
||||
build/nasal_err.o\
|
||||
build/nasal_ast.o\
|
||||
build/ast_visitor.o\
|
||||
build/bits_lib.o\
|
||||
build/ast_dumper.o\
|
||||
build/nasal_lexer.o\
|
||||
build/nasal_parse.o\
|
||||
build/nasal_import.o\
|
||||
build/optimizer.o\
|
||||
build/nasal_opcode.o\
|
||||
build/symbol_finder.o\
|
||||
build/nasal_codegen.o\
|
||||
build/nasal_gc.o\
|
||||
build/builtin.o\
|
||||
build/fg_props.o\
|
||||
build/io_lib.o\
|
||||
build/math_lib.o\
|
||||
build/unix_lib.o\
|
||||
build/dylib_lib.o\
|
||||
build/subprocess.o\
|
||||
build/json_lib.o\
|
||||
build/coroutine.o\
|
||||
build/nasal_type.o\
|
||||
build/nasal_vm.o\
|
||||
build/nasal_dbg.o\
|
||||
build/regex_lib.o\
|
||||
build/repl.o\
|
||||
build/cli.o\
|
||||
build/fs.o\
|
||||
build/util.o\
|
||||
build/main.o
|
||||
|
||||
|
||||
# for test
|
||||
nasal: $(NASAL_OBJECT) | build
|
||||
@if [ OS = "Darwin" ]; then\
|
||||
$(CXX) $(NASAL_OBJECT) -O3 -o nasal -ldl -lpthread -stdlib=libc++ -static-libstdc++;\
|
||||
else\
|
||||
$(CXX) $(NASAL_OBJECT) -O3 -o nasal -ldl -lpthread;\
|
||||
fi
|
||||
|
||||
nasal.exe: $(NASAL_OBJECT) | build
|
||||
$(CXX) $(NASAL_OBJECT) -O3 -o nasal.exe
|
||||
|
||||
build:
|
||||
@ if [ ! -d build ]; then mkdir build; fi
|
||||
|
||||
build/main.o: $(NASAL_HEADER) src/main.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/main.cpp -o build/main.o
|
||||
|
||||
build/cli.o: src/cli/cli.h src/cli/cli.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/cli/cli.cpp -o build/cli.o
|
||||
|
||||
build/util.o: src/util/util.h src/util/util.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/util/util.cpp -o build/util.o
|
||||
|
||||
build/fs.o: src/nasal.h src/util/util.h src/util/fs.h src/util/fs.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/util/fs.cpp -o build/fs.o
|
||||
|
||||
build/repl.o: $(NASAL_HEADER) src/repl/repl.h src/repl/repl.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/repl/repl.cpp -o build/repl.o
|
||||
|
||||
build/nasal_err.o: src/nasal.h src/repl/repl.h src/nasal_err.h src/nasal_err.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_err.cpp -o build/nasal_err.o
|
||||
|
||||
build/nasal_type.o:\
|
||||
src/nasal.h\
|
||||
src/util/util.h\
|
||||
src/nasal_type.h src/nasal_type.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_type.cpp -o build/nasal_type.o
|
||||
|
||||
build/nasal_gc.o:\
|
||||
src/nasal.h\
|
||||
src/util/util.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/nasal_gc.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_gc.cpp -o build/nasal_gc.o
|
||||
|
||||
build/nasal_import.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_ast.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_parse.h\
|
||||
src/util/util.h\
|
||||
src/util/fs.h\
|
||||
src/nasal_import.h src/nasal_import.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_import.cpp -o build/nasal_import.o
|
||||
|
||||
build/nasal_lexer.o: \
|
||||
src/nasal.h\
|
||||
src/repl/repl.h\
|
||||
src/util/util.h\
|
||||
src/util/fs.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_lexer.h src/nasal_lexer.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_lexer.cpp -o build/nasal_lexer.o
|
||||
|
||||
build/nasal_ast.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h src/nasal_ast.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_ast.cpp -o build/nasal_ast.o
|
||||
|
||||
build/builtin.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/util/util.h\
|
||||
src/natives/builtin.h\
|
||||
src/natives/builtin.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/builtin.cpp -o build/builtin.o
|
||||
|
||||
build/coroutine.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/coroutine.h src/natives/coroutine.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/coroutine.cpp -o build/coroutine.o
|
||||
|
||||
build/bits_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/bits_lib.h src/natives/bits_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/bits_lib.cpp -o build/bits_lib.o
|
||||
|
||||
build/math_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/math_lib.h src/natives/math_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/math_lib.cpp -o build/math_lib.o
|
||||
|
||||
build/io_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/util/fs.h\
|
||||
src/natives/io_lib.h src/natives/io_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/io_lib.cpp -o build/io_lib.o
|
||||
|
||||
build/dylib_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/util/util.h\
|
||||
src/util/fs.h\
|
||||
src/natives/dylib_lib.h src/natives/dylib_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/dylib_lib.cpp -o build/dylib_lib.o
|
||||
|
||||
build/json_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/util/util.h\
|
||||
src/natives/json_lib.h src/natives/json_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/json_lib.cpp -o build/json_lib.o
|
||||
|
||||
build/unix_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/unix_lib.h src/natives/unix_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/unix_lib.cpp -o build/unix_lib.o
|
||||
|
||||
build/regex_lib.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/regex_lib.h src/natives/regex_lib.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/regex_lib.cpp -o build/regex_lib.o
|
||||
|
||||
build/subprocess.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/subprocess.h src/natives/subprocess.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/subprocess.cpp -o build/subprocess.o
|
||||
|
||||
|
||||
build/fg_props.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_type.h\
|
||||
src/nasal_gc.h\
|
||||
src/natives/fg_props.h src/natives/fg_props.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/natives/fg_props.cpp -o build/fg_props.o
|
||||
|
||||
build/nasal_codegen.o: $(NASAL_HEADER) src/nasal_codegen.h src/nasal_codegen.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_codegen.cpp -o build/nasal_codegen.o
|
||||
|
||||
build/nasal_opcode.o: \
|
||||
src/nasal.h\
|
||||
src/natives/builtin.h\
|
||||
src/util/util.h\
|
||||
src/nasal_opcode.h src/nasal_opcode.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_opcode.cpp -o build/nasal_opcode.o
|
||||
|
||||
build/nasal_parse.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_ast.h\
|
||||
src/nasal_lexer.h\
|
||||
src/nasal_err.h\
|
||||
src/util/util.h\
|
||||
src/nasal_parse.h src/nasal_parse.cpp src/nasal_ast.h | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_parse.cpp -o build/nasal_parse.o
|
||||
|
||||
build/optimizer.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
src/optimizer.h src/optimizer.cpp src/nasal_ast.h | build
|
||||
$(CXX) $(CXXFLAGS) src/optimizer.cpp -o build/optimizer.o
|
||||
|
||||
build/symbol_finder.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
src/symbol_finder.h src/symbol_finder.cpp src/nasal_ast.h | build
|
||||
$(CXX) $(CXXFLAGS) src/symbol_finder.cpp -o build/symbol_finder.o
|
||||
|
||||
build/ast_visitor.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h src/ast_visitor.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/ast_visitor.cpp -o build/ast_visitor.o
|
||||
|
||||
build/ast_dumper.o: \
|
||||
src/nasal.h\
|
||||
src/nasal_err.h\
|
||||
src/nasal_ast.h\
|
||||
src/ast_visitor.h\
|
||||
src/util/util.h\
|
||||
src/ast_dumper.h src/ast_dumper.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/ast_dumper.cpp -o build/ast_dumper.o
|
||||
|
||||
build/nasal_vm.o: $(NASAL_HEADER) src/nasal_vm.h src/nasal_vm.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_vm.cpp -o build/nasal_vm.o
|
||||
|
||||
build/nasal_dbg.o: $(NASAL_HEADER) src/nasal_dbg.h src/nasal_dbg.cpp | build
|
||||
$(CXX) $(CXXFLAGS) src/nasal_dbg.cpp -o build/nasal_dbg.o
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ echo "[clean] nasal" && if [ -e nasal ]; then rm nasal; fi
|
||||
@ echo "[clean] nasal.exe" && if [ -e nasal.exe ]; then rm nasal.exe; fi
|
||||
@ rm $(NASAL_OBJECT)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@@ -303,6 +23,7 @@ test:
|
||||
@ ./nasal -t test/bigloop.nas
|
||||
@ ./nasal -t test/bp.nas
|
||||
@ ./nasal -d test/calc.nas
|
||||
@ ./nasal test/caller.nas
|
||||
@ ./nasal -e test/choice.nas
|
||||
@ ./nasal -e test/class.nas
|
||||
@ ./nasal -t -d test/console3D.nas 20
|
||||
|
||||
@@ -9,10 +9,10 @@ namespace nasal {
|
||||
namespace fib_module {
|
||||
|
||||
double fibonaci(double x) {
|
||||
if (x<=2) {
|
||||
if (x <= 2) {
|
||||
return x;
|
||||
}
|
||||
return fibonaci(x-1)+fibonaci(x-2);
|
||||
return fibonaci(x - 1) + fibonaci(x - 2);
|
||||
}
|
||||
|
||||
var fib(var* args, usize size, gc* ngc) {
|
||||
@@ -33,7 +33,7 @@ var quick_fib(var* args, usize size, gc* ngc) {
|
||||
}
|
||||
double a = 1, b = 1, res = 0;
|
||||
for (double i = 1; i<num; ++i) {
|
||||
res = a+b;
|
||||
res = a + b;
|
||||
a = b;
|
||||
b = res;
|
||||
}
|
||||
|
||||
@@ -54,14 +54,14 @@ public:
|
||||
#ifndef _WIN32
|
||||
unsigned char ch = 0;
|
||||
int nread = 0;
|
||||
if (peek_char!=-1) {
|
||||
if (peek_char != -1) {
|
||||
return 1;
|
||||
}
|
||||
int flag = fcntl(0, F_GETFL);
|
||||
fcntl(0, F_SETFL, flag|O_NONBLOCK);
|
||||
nread = read(0, &ch, 1);
|
||||
fcntl(0, F_SETFL, flag);
|
||||
if (nread==1) {
|
||||
if (nread == 1) {
|
||||
peek_char = ch;
|
||||
return 1;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
int noecho_getch() {
|
||||
#ifndef _WIN32
|
||||
int ch = 0;
|
||||
if (peek_char!=-1) {
|
||||
if (peek_char != -1) {
|
||||
ch = peek_char;
|
||||
peek_char = -1;
|
||||
return ch;
|
||||
|
||||
@@ -49,7 +49,7 @@ var test_ghost = func() {
|
||||
print("\n");
|
||||
set_ghost(ghost, 114); # success
|
||||
print("\n");
|
||||
for (var i = 0; i<256; i+=1) {
|
||||
for (var i = 0; i < 256; i += 1) {
|
||||
var temp = []; # try to trigger gc
|
||||
}
|
||||
print("\n");
|
||||
|
||||
@@ -3,7 +3,7 @@ use std.os;
|
||||
|
||||
var socket = func() {
|
||||
var lib = dylib.dlopen("libnasock");
|
||||
|
||||
|
||||
var sock = lib.nas_socket;
|
||||
var closesocket = lib.nas_closesocket;
|
||||
var shutdown = lib.nas_shutdown;
|
||||
|
||||
@@ -25,11 +25,11 @@ var nas_vec2_add(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=2 || v1.size()!=2)
|
||||
if (v0.size() != 2 || v1.size() != 2)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()+v1[0].num()));
|
||||
res.vec().elems.push_back(var::num(v0[1].num()+v1[1].num()));
|
||||
res.vec().elems.push_back(var::num(v0[0].num() + v1[0].num()));
|
||||
res.vec().elems.push_back(var::num(v0[1].num() + v1[1].num()));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ var nas_vec2_sub(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=2 || v1.size()!=2)
|
||||
if (v0.size() != 2 || v1.size() != 2)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()-v1[0].num()));
|
||||
@@ -51,7 +51,7 @@ var nas_vec2_mult(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=2 || v1.size()!=2)
|
||||
if (v0.size() != 2 || v1.size() != 2)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()*v1[0].num()));
|
||||
@@ -64,7 +64,7 @@ var nas_vec2_div(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=2 || v1.size()!=2)
|
||||
if (v0.size() != 2 || v1.size() != 2)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()/v1[0].num()));
|
||||
@@ -76,7 +76,7 @@ var nas_vec2_neg(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=2)
|
||||
if (v0.size() != 2)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(-v0[0].num()));
|
||||
@@ -88,14 +88,14 @@ var nas_vec2_norm(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=2)
|
||||
if (v0.size() != 2)
|
||||
return nil;
|
||||
auto x = v0[0].num();
|
||||
auto y = v0[1].num();
|
||||
auto t = std::sqrt(x*x+y*y);
|
||||
auto t = std::sqrt(x * x + y * y);
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(x/t));
|
||||
res.vec().elems.push_back(var::num(y/t));
|
||||
res.vec().elems.push_back(var::num(x / t));
|
||||
res.vec().elems.push_back(var::num(y / t));
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -103,11 +103,11 @@ var nas_vec2_len(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=2)
|
||||
if (v0.size() != 2)
|
||||
return nil;
|
||||
auto x = v0[0].num();
|
||||
auto y = v0[1].num();
|
||||
return var::num(std::sqrt(x*x+y*y));
|
||||
return var::num(std::sqrt(x * x + y * y));
|
||||
}
|
||||
|
||||
var nas_vec2_dot(var* args, usize size, gc* ngc) {
|
||||
@@ -115,9 +115,9 @@ var nas_vec2_dot(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=2 || v1.size()!=2)
|
||||
if (v0.size() != 2 || v1.size() != 2)
|
||||
return nil;
|
||||
return var::num(v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num());
|
||||
return var::num(v0[0].num() * v1[0].num() + v0[1].num() * v1[1].num());
|
||||
}
|
||||
|
||||
var nas_vec3_add(var* args, usize size, gc* ngc) {
|
||||
@@ -125,7 +125,7 @@ var nas_vec3_add(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=3 || v1.size()!=3)
|
||||
if (v0.size() != 3 || v1.size() != 3)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()+v1[0].num()));
|
||||
@@ -139,7 +139,7 @@ var nas_vec3_sub(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=3 || v1.size()!=3)
|
||||
if (v0.size() != 3 || v1.size() != 3)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()-v1[0].num()));
|
||||
@@ -153,7 +153,7 @@ var nas_vec3_mult(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=3 || v1.size()!=3)
|
||||
if (v0.size() != 3 || v1.size() != 3)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()*v1[0].num()));
|
||||
@@ -167,7 +167,7 @@ var nas_vec3_div(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=3 || v1.size()!=3)
|
||||
if (v0.size() != 3 || v1.size() != 3)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(v0[0].num()/v1[0].num()));
|
||||
@@ -180,7 +180,7 @@ var nas_vec3_neg(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
res.vec().elems.push_back(var::num(-v0[0].num()));
|
||||
@@ -193,7 +193,7 @@ var nas_vec3_norm(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
auto x = v0[0].num();
|
||||
auto y = v0[1].num();
|
||||
@@ -210,7 +210,7 @@ var nas_vec3_len(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
auto x = v0[0].num();
|
||||
auto y = v0[1].num();
|
||||
@@ -222,7 +222,7 @@ var nas_rotate_x(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
auto angle = args[1].num();
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
@@ -236,7 +236,7 @@ var nas_rotate_y(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
auto angle = args[1].num();
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
@@ -250,7 +250,7 @@ var nas_rotate_z(var* args, usize size, gc* ngc) {
|
||||
if (!args[0].is_vec())
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
if (v0.size()!=3)
|
||||
if (v0.size() != 3)
|
||||
return nil;
|
||||
auto angle = args[1].num();
|
||||
var res = ngc->alloc(vm_type::vm_vec);
|
||||
@@ -265,7 +265,7 @@ var nas_vec3_dot(var* args, usize size, gc* ngc) {
|
||||
return nil;
|
||||
auto& v0 = args[0].vec().elems;
|
||||
auto& v1 = args[1].vec().elems;
|
||||
if (v0.size()!=3 || v1.size()!=3)
|
||||
if (v0.size() != 3 || v1.size() != 3)
|
||||
return nil;
|
||||
return var::num(v0[0].num()*v1[0].num()+v0[1].num()*v1[1].num()+v0[2].num()*v1[2].num());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "nasal_ast.h"
|
||||
#include "ast.h"
|
||||
#include "ast_visitor.h"
|
||||
|
||||
namespace nasal {
|
||||
@@ -11,7 +11,7 @@ namespace nasal {
|
||||
enum class expr_type {
|
||||
ast_null = 0, // null node
|
||||
ast_use, // use statement
|
||||
ast_block, // code block
|
||||
ast_block, // code block
|
||||
ast_nil, // nil keyword
|
||||
ast_num, // number, basic value type
|
||||
ast_str, // string, basic value type
|
||||
@@ -61,15 +61,18 @@ class expr {
|
||||
protected:
|
||||
span nd_loc;
|
||||
expr_type nd_type;
|
||||
bool in_curve;
|
||||
|
||||
public:
|
||||
expr(const span& location, expr_type node_type):
|
||||
nd_loc(location), nd_type(node_type) {}
|
||||
nd_loc(location), nd_type(node_type), in_curve(false) {}
|
||||
virtual ~expr() = default;
|
||||
void set_begin(u64 line, u64 column) {
|
||||
nd_loc.begin_line = line;
|
||||
nd_loc.begin_column = column;
|
||||
}
|
||||
void set_in_curve() { in_curve = true; }
|
||||
auto get_in_curve() const { return in_curve; }
|
||||
const auto& get_location() const { return nd_loc; }
|
||||
const auto get_line() const { return nd_loc.begin_line; }
|
||||
auto get_type() const { return nd_type; }
|
||||
@@ -151,19 +151,25 @@ bool ast_format::visit_parameter(parameter* node) {
|
||||
|
||||
bool ast_format::visit_ternary_operator(ternary_operator* node) {
|
||||
dump_formating_node_info(node, "ternary operator");
|
||||
out << "(";
|
||||
if (node->get_in_curve()) {
|
||||
out << "(";
|
||||
}
|
||||
node->get_condition()->accept(this);
|
||||
out << " ? ";
|
||||
node->get_left()->accept(this);
|
||||
out << " : ";
|
||||
node->get_right()->accept(this);
|
||||
out << ")";
|
||||
if (node->get_in_curve()) {
|
||||
out << ")";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_format::visit_binary_operator(binary_operator* node) {
|
||||
dump_formating_node_info(node, "binary operator");
|
||||
out << "(";
|
||||
if (node->get_in_curve()) {
|
||||
out << "(";
|
||||
}
|
||||
node->get_left()->accept(this);
|
||||
switch(node->get_operator_type()) {
|
||||
case binary_operator::kind::add: out << " + "; break;
|
||||
@@ -185,18 +191,26 @@ bool ast_format::visit_binary_operator(binary_operator* node) {
|
||||
case binary_operator::kind::null_chain: out << " ?? "; break;
|
||||
}
|
||||
node->get_right()->accept(this);
|
||||
out << ")";
|
||||
if (node->get_in_curve()) {
|
||||
out << ")";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_format::visit_unary_operator(unary_operator* node) {
|
||||
dump_formating_node_info(node, "unary operator");
|
||||
if (node->get_in_curve()) {
|
||||
out << "(";
|
||||
}
|
||||
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);
|
||||
if (node->get_in_curve()) {
|
||||
out << ")";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "nasal_ast.h"
|
||||
#include "ast.h"
|
||||
|
||||
namespace nasal {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "nasal.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "ast/ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "util/util.h"
|
||||
#include "cli/cli.h"
|
||||
#include "ast_format.h"
|
||||
#include "ast/ast_format.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
@@ -37,7 +37,7 @@ int main(i32 argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
// the first argument is the executable itself, ignore it
|
||||
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
|
||||
if (config.has(nasal::cli::option::cli_help)) {
|
||||
|
||||
10
src/main.cpp
10
src/main.cpp
@@ -3,11 +3,11 @@
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/ast_visitor.h"
|
||||
#include "ast/ast_dumper.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "ast_visitor.h"
|
||||
#include "ast_dumper.h"
|
||||
#include "symbol_finder.h"
|
||||
#include "optimizer.h"
|
||||
#include "nasal_codegen.h"
|
||||
@@ -55,7 +55,7 @@ void execute(const nasal::cli::cli_config& config) {
|
||||
std::cout << " " << file << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// optimizer does simple optimization on ast
|
||||
auto opt = std::make_unique<nasal::optimizer>();
|
||||
opt->do_optimization(parse.tree());
|
||||
@@ -120,7 +120,7 @@ i32 main(i32 argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
// the first argument is the executable itself, ignore it
|
||||
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
|
||||
if (argc == 2) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __nasver__
|
||||
#define __nasver__ "11.3.3"
|
||||
#define __nasver__ "11.3.4"
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
@@ -54,13 +54,13 @@ void codegen::check_id_exist(identifier* node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (local_symbol_find(name)>=0) {
|
||||
if (local_symbol_find(name) >= 0) {
|
||||
return;
|
||||
}
|
||||
if (upvalue_symbol_find(name)>=0) {
|
||||
if (upvalue_symbol_find(name) >= 0) {
|
||||
return;
|
||||
}
|
||||
if (global_symbol_find(name)>=0) {
|
||||
if (global_symbol_find(name) >= 0) {
|
||||
return;
|
||||
}
|
||||
die("undefined symbol \""
|
||||
@@ -148,7 +148,7 @@ i64 codegen::upvalue_symbol_find(const std::string& name) {
|
||||
// but we check the local size in codegen::func_gen
|
||||
i64 index = -1;
|
||||
usize size = local.size();
|
||||
if (size<=1) {
|
||||
if (size <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -211,21 +211,18 @@ void codegen::func_gen(function* node) {
|
||||
bool checked_dynamic = false;
|
||||
std::unordered_map<std::string, bool> argname;
|
||||
for (auto tmp : node->get_parameter_list()) {
|
||||
if (tmp->get_parameter_type()==
|
||||
parameter::kind::default_parameter) {
|
||||
if (tmp->get_parameter_type() == parameter::kind::default_parameter) {
|
||||
checked_default = true;
|
||||
} else if (tmp->get_parameter_type()==
|
||||
parameter::kind::dynamic_parameter) {
|
||||
} else if (tmp->get_parameter_type() == parameter::kind::dynamic_parameter) {
|
||||
checked_dynamic = true;
|
||||
}
|
||||
// check default parameter and dynamic parameter
|
||||
if (checked_default &&
|
||||
tmp->get_parameter_type()!=
|
||||
parameter::kind::default_parameter) {
|
||||
tmp->get_parameter_type() != parameter::kind::default_parameter) {
|
||||
die("must use default parameter here", tmp);
|
||||
}
|
||||
if (checked_dynamic &&
|
||||
tmp!=node->get_parameter_list().back()) {
|
||||
tmp != node->get_parameter_list().back()) {
|
||||
die("dynamic parameter must be the last one", tmp);
|
||||
}
|
||||
// check redefinition
|
||||
@@ -241,7 +238,7 @@ void codegen::func_gen(function* node) {
|
||||
emit(op_newf, 0, node->get_location());
|
||||
const auto lsize = code.size();
|
||||
emit(op_intl, 0, node->get_location());
|
||||
|
||||
|
||||
// add special keyword 'me' into symbol table
|
||||
// this symbol is only used in local scope(function's scope)
|
||||
// this keyword is set to nil as default value
|
||||
@@ -305,7 +302,7 @@ void codegen::func_gen(function* node) {
|
||||
// the local scope should not cause stack overflow
|
||||
// and should not greater than upvalue's max size(65536)
|
||||
code[lsize].num = local.back().size();
|
||||
if (local.back().size()>=VM_STACK_DEPTH || local.back().size()>=UINT16_MAX) {
|
||||
if (local.back().size() >= VM_STACK_DEPTH || local.back().size() >= UINT16_MAX) {
|
||||
die("too many local variants: " +
|
||||
std::to_string(local.back().size()),
|
||||
block
|
||||
@@ -314,7 +311,7 @@ void codegen::func_gen(function* node) {
|
||||
local.pop_back();
|
||||
|
||||
if (!block->get_expressions().size() ||
|
||||
block->get_expressions().back()->get_type()!=expr_type::ast_ret) {
|
||||
block->get_expressions().back()->get_type() != expr_type::ast_ret) {
|
||||
emit(op_pnil, 0, block->get_location());
|
||||
emit(op_ret, 0, block->get_location());
|
||||
}
|
||||
@@ -323,7 +320,7 @@ void codegen::func_gen(function* node) {
|
||||
|
||||
void codegen::call_gen(call_expr* node) {
|
||||
calc_gen(node->get_first());
|
||||
if (code.size() && code.back().op==op_callb) {
|
||||
if (code.size() && code.back().op == op_callb) {
|
||||
return;
|
||||
}
|
||||
for (auto i : node->get_calls()) {
|
||||
@@ -355,15 +352,15 @@ void codegen::call_identifier(identifier* node) {
|
||||
}
|
||||
|
||||
i64 index;
|
||||
if ((index = local_symbol_find(name))>=0) {
|
||||
if ((index = local_symbol_find(name)) >= 0) {
|
||||
emit(op_calll, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index = upvalue_symbol_find(name))>=0) {
|
||||
if ((index = upvalue_symbol_find(name)) >= 0) {
|
||||
emit(op_upval, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
if ((index = global_symbol_find(name))>=0) {
|
||||
if ((index = global_symbol_find(name)) >= 0) {
|
||||
emit(op_callg, index, node->get_location());
|
||||
return;
|
||||
}
|
||||
@@ -703,7 +700,7 @@ void codegen::gen_assignment_equal_statement(assignment_expr* node) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// generate symbol load
|
||||
calc_gen(node->get_right());
|
||||
// get memory space of left identifier
|
||||
@@ -1426,7 +1423,7 @@ void codegen::print(std::ostream& out) {
|
||||
for (const auto& str : const_string_table) {
|
||||
out << " .symbol \"" << util::rawstr(str) << "\"\n";
|
||||
}
|
||||
|
||||
|
||||
// print blank line
|
||||
if (const_number_table.size() || const_string_table.size()) {
|
||||
out << "\n";
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "nasal_err.h"
|
||||
#include "nasal_opcode.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "ast_visitor.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/ast_visitor.h"
|
||||
#include "symbol_finder.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
@@ -103,7 +103,7 @@ private:
|
||||
std::list<std::unordered_map<std::string, u64>> local;
|
||||
|
||||
void check_id_exist(identifier*);
|
||||
|
||||
|
||||
void die(const std::string& info, expr* node) {
|
||||
err.err("code", node->get_location(), info);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ void operand_line_counter::dump_all_code_line_counter(std::ostream& os) const {
|
||||
for (usize j = 0; j<context.size(); ++j) {
|
||||
os << " " << std::right << std::setw(pad_length);
|
||||
os << std::setfill(' ');
|
||||
os << (counter[j]==0? "":std::to_string(counter[j]));
|
||||
os << (counter[j] == 0 ? "" : std::to_string(counter[j]));
|
||||
os << " " << context[j] << "\n";
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void operand_line_counter::dump_this_file_line_counter(std::ostream& os) const {
|
||||
for (usize i = 0; i<context.size(); ++i) {
|
||||
os << " " << std::right << std::setw(pad_length);
|
||||
os << std::setfill(' ');
|
||||
os << (counter[i]==0? "":std::to_string(counter[i]));
|
||||
os << (counter[i] == 0 ? "" : std::to_string(counter[i]));
|
||||
os << " " << context[i] << "\n";
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,9 @@ std::vector<std::string> dbg::parse(const std::string& cmd) {
|
||||
usize last = 0, pos = cmd.find(" ", 0);
|
||||
while (pos!=std::string::npos) {
|
||||
if (pos>last) {
|
||||
res.push_back(cmd.substr(last, pos-last));
|
||||
res.push_back(cmd.substr(last, pos - last));
|
||||
}
|
||||
last = pos+1;
|
||||
last = pos + 1;
|
||||
pos = cmd.find(" ", last);
|
||||
}
|
||||
if (last<cmd.length()) {
|
||||
|
||||
@@ -121,7 +121,7 @@ void filestream::load(const std::string& f) {
|
||||
if (file==f) { // don't need to load a loaded file
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// update file name
|
||||
file = f;
|
||||
|
||||
@@ -149,7 +149,7 @@ void filestream::load(const std::string& f) {
|
||||
std::cerr << red << "src: " << reset << "cannot open <" << f << ">\n";
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
||||
while (!in.eof()) {
|
||||
std::string line;
|
||||
std::getline(in, line);
|
||||
|
||||
@@ -244,7 +244,7 @@ code_block* linker::import_nasal_lib() {
|
||||
if (check_exist_or_record_file(path)) {
|
||||
return new code_block({0, 0, 0, 0, path});
|
||||
}
|
||||
|
||||
|
||||
// start importing...
|
||||
lexer nasal_lexer;
|
||||
parse nasal_parser;
|
||||
@@ -304,7 +304,7 @@ std::string linker::generate_module_name(const std::string& file_path) {
|
||||
auto module_name = split_position==std::string::npos?
|
||||
file_path.substr(0, suffix_position):
|
||||
file_path.substr(split_position+1, suffix_position-split_position-1);
|
||||
|
||||
|
||||
// check validation of module name
|
||||
if (!module_name.length()) {
|
||||
err.warn("link",
|
||||
@@ -352,7 +352,7 @@ definition_expr* linker::generate_module_definition(code_block* block) {
|
||||
block->get_location(),
|
||||
generate_module_name(block->get_location().file)
|
||||
));
|
||||
|
||||
|
||||
// (func() {...})();
|
||||
auto call = new call_expr(block->get_location());
|
||||
// func() {...}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#endif
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "ast/ast.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "symbol_finder.h"
|
||||
|
||||
@@ -16,7 +16,7 @@ bool lexer::skip(char c) {
|
||||
}
|
||||
|
||||
bool lexer::is_id(char c) {
|
||||
return (c=='_') || std::isalpha(c) || (c<0);
|
||||
return (c=='_') || std::isalpha(c) || (c<0);
|
||||
}
|
||||
|
||||
bool lexer::is_hex(char c) {
|
||||
|
||||
@@ -103,94 +103,94 @@ enum opcode_type: u8 {
|
||||
};
|
||||
|
||||
static std::unordered_map<opcode_type, std::string> operand_name_table = {
|
||||
{opcode_type::op_exit, "exit "},
|
||||
{opcode_type::op_repl, "repl "},
|
||||
{opcode_type::op_intl, "intl "},
|
||||
{opcode_type::op_loadg, "loadg "},
|
||||
{opcode_type::op_loadl, "loadl "},
|
||||
{opcode_type::op_loadu, "loadu "},
|
||||
{opcode_type::op_dup, "dup "},
|
||||
{opcode_type::op_pnum, "pnum "},
|
||||
{opcode_type::op_pnil, "pnil "},
|
||||
{opcode_type::op_pstr, "pstr "},
|
||||
{opcode_type::op_newv, "newv "},
|
||||
{opcode_type::op_newh, "newh "},
|
||||
{opcode_type::op_newf, "newf "},
|
||||
{opcode_type::op_happ, "happ "},
|
||||
{opcode_type::op_para, "para "},
|
||||
{opcode_type::op_deft, "def "},
|
||||
{opcode_type::op_dyn, "dyn "},
|
||||
{opcode_type::op_lnot, "lnot "},
|
||||
{opcode_type::op_usub, "usub "},
|
||||
{opcode_type::op_bnot, "bitnot"},
|
||||
{opcode_type::op_btor, "bitor "},
|
||||
{opcode_type::op_btxor, "bitxor"},
|
||||
{opcode_type::op_btand, "bitand"},
|
||||
{opcode_type::op_add, "add "},
|
||||
{opcode_type::op_sub, "sub "},
|
||||
{opcode_type::op_mul, "mult "},
|
||||
{opcode_type::op_div, "div "},
|
||||
{opcode_type::op_lnk, "lnk "},
|
||||
{opcode_type::op_addc, "addc "},
|
||||
{opcode_type::op_subc, "subc "},
|
||||
{opcode_type::op_mulc, "multc "},
|
||||
{opcode_type::op_divc, "divc "},
|
||||
{opcode_type::op_lnkc, "lnkc "},
|
||||
{opcode_type::op_addeq, "addeq "},
|
||||
{opcode_type::op_subeq, "subeq "},
|
||||
{opcode_type::op_muleq, "muleq "},
|
||||
{opcode_type::op_diveq, "diveq "},
|
||||
{opcode_type::op_lnkeq, "lnkeq "},
|
||||
{opcode_type::op_exit, "exit "},
|
||||
{opcode_type::op_repl, "repl "},
|
||||
{opcode_type::op_intl, "intl "},
|
||||
{opcode_type::op_loadg, "loadg "},
|
||||
{opcode_type::op_loadl, "loadl "},
|
||||
{opcode_type::op_loadu, "loadu "},
|
||||
{opcode_type::op_dup, "dup "},
|
||||
{opcode_type::op_pnum, "pnum "},
|
||||
{opcode_type::op_pnil, "pnil "},
|
||||
{opcode_type::op_pstr, "pstr "},
|
||||
{opcode_type::op_newv, "newv "},
|
||||
{opcode_type::op_newh, "newh "},
|
||||
{opcode_type::op_newf, "newf "},
|
||||
{opcode_type::op_happ, "happ "},
|
||||
{opcode_type::op_para, "para "},
|
||||
{opcode_type::op_deft, "def "},
|
||||
{opcode_type::op_dyn, "dyn "},
|
||||
{opcode_type::op_lnot, "lnot "},
|
||||
{opcode_type::op_usub, "usub "},
|
||||
{opcode_type::op_bnot, "bitnot"},
|
||||
{opcode_type::op_btor, "bitor "},
|
||||
{opcode_type::op_btxor, "bitxor"},
|
||||
{opcode_type::op_btand, "bitand"},
|
||||
{opcode_type::op_add, "add "},
|
||||
{opcode_type::op_sub, "sub "},
|
||||
{opcode_type::op_mul, "mult "},
|
||||
{opcode_type::op_div, "div "},
|
||||
{opcode_type::op_lnk, "lnk "},
|
||||
{opcode_type::op_addc, "addc "},
|
||||
{opcode_type::op_subc, "subc "},
|
||||
{opcode_type::op_mulc, "multc "},
|
||||
{opcode_type::op_divc, "divc "},
|
||||
{opcode_type::op_lnkc, "lnkc "},
|
||||
{opcode_type::op_addeq, "addeq "},
|
||||
{opcode_type::op_subeq, "subeq "},
|
||||
{opcode_type::op_muleq, "muleq "},
|
||||
{opcode_type::op_diveq, "diveq "},
|
||||
{opcode_type::op_lnkeq, "lnkeq "},
|
||||
{opcode_type::op_btandeq, "bandeq"},
|
||||
{opcode_type::op_btoreq, "boreq "},
|
||||
{opcode_type::op_btoreq, "boreq "},
|
||||
{opcode_type::op_btxoreq, "bxoreq"},
|
||||
{opcode_type::op_addeqc, "addeqc"},
|
||||
{opcode_type::op_subeqc, "subeqc"},
|
||||
{opcode_type::op_muleqc, "muleqc"},
|
||||
{opcode_type::op_diveqc, "diveqc"},
|
||||
{opcode_type::op_lnkeqc, "lnkeqc"},
|
||||
{opcode_type::op_addecp, "addecp"},
|
||||
{opcode_type::op_subecp, "subecp"},
|
||||
{opcode_type::op_mulecp, "mulecp"},
|
||||
{opcode_type::op_divecp, "divecp"},
|
||||
{opcode_type::op_lnkecp, "lnkecp"},
|
||||
{opcode_type::op_meq, "meq "},
|
||||
{opcode_type::op_eq, "eq "},
|
||||
{opcode_type::op_neq, "neq "},
|
||||
{opcode_type::op_less, "less "},
|
||||
{opcode_type::op_leq, "leq "},
|
||||
{opcode_type::op_grt, "grt "},
|
||||
{opcode_type::op_geq, "geq "},
|
||||
{opcode_type::op_lessc, "lessc "},
|
||||
{opcode_type::op_leqc, "leqc "},
|
||||
{opcode_type::op_grtc, "grtc "},
|
||||
{opcode_type::op_geqc, "geqc "},
|
||||
{opcode_type::op_pop, "pop "},
|
||||
{opcode_type::op_jmp, "jmp "},
|
||||
{opcode_type::op_jt, "jt "},
|
||||
{opcode_type::op_jf, "jf "},
|
||||
{opcode_type::op_cnt, "cnt "},
|
||||
{opcode_type::op_findex, "findx "},
|
||||
{opcode_type::op_feach, "feach "},
|
||||
{opcode_type::op_callg, "callg "},
|
||||
{opcode_type::op_calll, "calll "},
|
||||
{opcode_type::op_upval, "upval "},
|
||||
{opcode_type::op_callv, "callv "},
|
||||
{opcode_type::op_callvi, "callvi"},
|
||||
{opcode_type::op_callh, "callh "},
|
||||
{opcode_type::op_callfv, "callfv"},
|
||||
{opcode_type::op_callfh, "callfh"},
|
||||
{opcode_type::op_callb, "callb "},
|
||||
{opcode_type::op_slcbeg, "slcbeg"},
|
||||
{opcode_type::op_slcend, "slcend"},
|
||||
{opcode_type::op_slc, "slice "},
|
||||
{opcode_type::op_slc2, "slice2"},
|
||||
{opcode_type::op_mcallg, "mcallg"},
|
||||
{opcode_type::op_mcalll, "mcalll"},
|
||||
{opcode_type::op_mupval, "mupval"},
|
||||
{opcode_type::op_mcallv, "mcallv"},
|
||||
{opcode_type::op_mcallh, "mcallh"},
|
||||
{opcode_type::op_ret, "ret "}
|
||||
{opcode_type::op_addeqc, "addeqc"},
|
||||
{opcode_type::op_subeqc, "subeqc"},
|
||||
{opcode_type::op_muleqc, "muleqc"},
|
||||
{opcode_type::op_diveqc, "diveqc"},
|
||||
{opcode_type::op_lnkeqc, "lnkeqc"},
|
||||
{opcode_type::op_addecp, "addecp"},
|
||||
{opcode_type::op_subecp, "subecp"},
|
||||
{opcode_type::op_mulecp, "mulecp"},
|
||||
{opcode_type::op_divecp, "divecp"},
|
||||
{opcode_type::op_lnkecp, "lnkecp"},
|
||||
{opcode_type::op_meq, "meq "},
|
||||
{opcode_type::op_eq, "eq "},
|
||||
{opcode_type::op_neq, "neq "},
|
||||
{opcode_type::op_less, "less "},
|
||||
{opcode_type::op_leq, "leq "},
|
||||
{opcode_type::op_grt, "grt "},
|
||||
{opcode_type::op_geq, "geq "},
|
||||
{opcode_type::op_lessc, "lessc "},
|
||||
{opcode_type::op_leqc, "leqc "},
|
||||
{opcode_type::op_grtc, "grtc "},
|
||||
{opcode_type::op_geqc, "geqc "},
|
||||
{opcode_type::op_pop, "pop "},
|
||||
{opcode_type::op_jmp, "jmp "},
|
||||
{opcode_type::op_jt, "jt "},
|
||||
{opcode_type::op_jf, "jf "},
|
||||
{opcode_type::op_cnt, "cnt "},
|
||||
{opcode_type::op_findex, "findx "},
|
||||
{opcode_type::op_feach, "feach "},
|
||||
{opcode_type::op_callg, "callg "},
|
||||
{opcode_type::op_calll, "calll "},
|
||||
{opcode_type::op_upval, "upval "},
|
||||
{opcode_type::op_callv, "callv "},
|
||||
{opcode_type::op_callvi, "callvi"},
|
||||
{opcode_type::op_callh, "callh "},
|
||||
{opcode_type::op_callfv, "callfv"},
|
||||
{opcode_type::op_callfh, "callfh"},
|
||||
{opcode_type::op_callb, "callb "},
|
||||
{opcode_type::op_slcbeg, "slcbeg"},
|
||||
{opcode_type::op_slcend, "slcend"},
|
||||
{opcode_type::op_slc, "slice "},
|
||||
{opcode_type::op_slc2, "slice2"},
|
||||
{opcode_type::op_mcallg, "mcallg"},
|
||||
{opcode_type::op_mcalll, "mcalll"},
|
||||
{opcode_type::op_mupval, "mupval"},
|
||||
{opcode_type::op_mcallv, "mcallv"},
|
||||
{opcode_type::op_mcallh, "mcallh"},
|
||||
{opcode_type::op_ret, "ret "}
|
||||
};
|
||||
|
||||
struct opcode {
|
||||
@@ -212,7 +212,7 @@ private:
|
||||
inline static const nasal_builtin_table* natives = nullptr;
|
||||
inline static const std::string* files = nullptr;
|
||||
inline static std::vector<std::string> global_variable;
|
||||
|
||||
|
||||
public:
|
||||
codestream(const opcode& c, const u64 i): code(c), index(i) {}
|
||||
static void set(const f64*,
|
||||
|
||||
2345
src/nasal_parse.cpp
2345
src/nasal_parse.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,169 +1,169 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "nasal.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_err.h"
|
||||
|
||||
namespace nasal {
|
||||
|
||||
class parse {
|
||||
|
||||
#define thisspan (toks[ptr].loc)
|
||||
#define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc)
|
||||
|
||||
private:
|
||||
u64 ptr;
|
||||
u64 in_func_depth; // count function block
|
||||
u64 in_loop_depth; // count loop block
|
||||
const token* toks;
|
||||
code_block* root;
|
||||
error err;
|
||||
|
||||
private:
|
||||
const std::unordered_map<tok, std::string> token_name_mapper = {
|
||||
{tok::tk_true , "true" },
|
||||
{tok::tk_false , "false" },
|
||||
{tok::tk_use , "use" },
|
||||
{tok::tk_for , "for" },
|
||||
{tok::tk_forindex, "forindex"},
|
||||
{tok::tk_foreach , "foreach" },
|
||||
{tok::tk_while , "while" },
|
||||
{tok::tk_var , "var" },
|
||||
{tok::tk_func , "func" },
|
||||
{tok::tk_brk , "break" },
|
||||
{tok::tk_cont , "continue"},
|
||||
{tok::tk_ret , "return" },
|
||||
{tok::tk_if , "if" },
|
||||
{tok::tk_elsif , "elsif" },
|
||||
{tok::tk_else , "else" },
|
||||
{tok::tk_nil , "nil" },
|
||||
{tok::tk_lcurve , "(" },
|
||||
{tok::tk_rcurve , ")" },
|
||||
{tok::tk_lbracket, "[" },
|
||||
{tok::tk_rbracket, "]" },
|
||||
{tok::tk_lbrace , "{" },
|
||||
{tok::tk_rbrace , "}" },
|
||||
{tok::tk_semi , ";" },
|
||||
{tok::tk_and , "and" },
|
||||
{tok::tk_or , "or" },
|
||||
{tok::tk_comma , "," },
|
||||
{tok::tk_dot , "." },
|
||||
{tok::tk_ellipsis, "..." },
|
||||
{tok::tk_quesmark, "?" },
|
||||
{tok::tk_quesques, "??" },
|
||||
{tok::tk_quesdot , "?." },
|
||||
{tok::tk_colon , ":" },
|
||||
{tok::tk_add , "+" },
|
||||
{tok::tk_sub , "-" },
|
||||
{tok::tk_mult , "*" },
|
||||
{tok::tk_div , "/" },
|
||||
{tok::tk_floater , "~" },
|
||||
{tok::tk_btand , "&" },
|
||||
{tok::tk_btor , "|" },
|
||||
{tok::tk_btxor , "^" },
|
||||
{tok::tk_not , "!" },
|
||||
{tok::tk_eq , "=" },
|
||||
{tok::tk_addeq , "+=" },
|
||||
{tok::tk_subeq , "-=" },
|
||||
{tok::tk_multeq , "*=" },
|
||||
{tok::tk_diveq , "/=" },
|
||||
{tok::tk_lnkeq , "~=" },
|
||||
{tok::tk_btandeq , "&=" },
|
||||
{tok::tk_btoreq , "|=" },
|
||||
{tok::tk_btxoreq , "^=" },
|
||||
{tok::tk_cmpeq , "==" },
|
||||
{tok::tk_neq , "!=" },
|
||||
{tok::tk_less , "<" },
|
||||
{tok::tk_leq , "<=" },
|
||||
{tok::tk_grt , ">" },
|
||||
{tok::tk_geq , ">=" }
|
||||
};
|
||||
|
||||
private:
|
||||
void die(const span&, const std::string&);
|
||||
void next();
|
||||
void match(tok, const char* info = nullptr);
|
||||
bool lookahead(tok);
|
||||
bool lookahead_expression();
|
||||
bool is_call(tok);
|
||||
bool check_comma(const tok*);
|
||||
bool check_tuple();
|
||||
bool check_func_end(expr*);
|
||||
bool check_in_curve_multi_definition();
|
||||
bool check_special_call();
|
||||
bool need_semi_check(expr*);
|
||||
void update_location(expr*);
|
||||
|
||||
private:
|
||||
use_stmt* use_stmt_gen();
|
||||
null_expr* null();
|
||||
nil_expr* nil();
|
||||
number_literal* num();
|
||||
string_literal* str();
|
||||
identifier* id();
|
||||
bool_literal* bools();
|
||||
vector_expr* vec();
|
||||
hash_expr* hash();
|
||||
hash_pair* pair();
|
||||
function* func();
|
||||
void params(function*);
|
||||
expr* lcurve_expr();
|
||||
expr* expression();
|
||||
code_block* expression_block();
|
||||
expr* calc();
|
||||
expr* bitwise_or();
|
||||
expr* bitwise_xor();
|
||||
expr* bitwise_and();
|
||||
expr* or_expr();
|
||||
expr* and_expr();
|
||||
expr* cmp_expr();
|
||||
expr* null_chain_expr();
|
||||
expr* additive_expr();
|
||||
expr* multive_expr();
|
||||
unary_operator* unary();
|
||||
expr* scalar();
|
||||
call* call_scalar();
|
||||
call_hash* callh();
|
||||
null_access* null_access_call();
|
||||
call_vector* callv();
|
||||
call_function* callf();
|
||||
slice_vector* subvec();
|
||||
expr* definition();
|
||||
multi_identifier* incurve_def();
|
||||
multi_identifier* outcurve_def();
|
||||
multi_identifier* multi_id();
|
||||
tuple_expr* multi_scalar();
|
||||
multi_assign* multi_assignment();
|
||||
expr* loop();
|
||||
while_expr* while_loop();
|
||||
for_expr* for_loop();
|
||||
forei_expr* forei_loop();
|
||||
iter_expr* iter_gen();
|
||||
condition_expr* cond();
|
||||
continue_expr* continue_expression();
|
||||
break_expr* break_expression();
|
||||
return_expr* return_expression();
|
||||
|
||||
public:
|
||||
code_block* tree() {return root;}
|
||||
|
||||
// swap root pointer with another pointer(maybe nullptr)
|
||||
code_block* swap(code_block* another) {
|
||||
auto res = root;
|
||||
root = another;
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
parse(): ptr(0), in_func_depth(0),
|
||||
in_loop_depth(0), toks(nullptr),
|
||||
root(nullptr) {}
|
||||
~parse() {delete root;}
|
||||
const error& compile(const lexer&);
|
||||
static void easter_egg();
|
||||
};
|
||||
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "nasal.h"
|
||||
#include "ast/ast.h"
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_err.h"
|
||||
|
||||
namespace nasal {
|
||||
|
||||
class parse {
|
||||
|
||||
#define thisspan (toks[ptr].loc)
|
||||
#define prevspan (ptr!=0? toks[ptr-1].loc:toks[ptr].loc)
|
||||
|
||||
private:
|
||||
u64 ptr;
|
||||
u64 in_func_depth; // count function block
|
||||
u64 in_loop_depth; // count loop block
|
||||
const token* toks;
|
||||
code_block* root;
|
||||
error err;
|
||||
|
||||
private:
|
||||
const std::unordered_map<tok, std::string> token_name_mapper = {
|
||||
{tok::tk_true , "true" },
|
||||
{tok::tk_false , "false" },
|
||||
{tok::tk_use , "use" },
|
||||
{tok::tk_for , "for" },
|
||||
{tok::tk_forindex, "forindex"},
|
||||
{tok::tk_foreach , "foreach" },
|
||||
{tok::tk_while , "while" },
|
||||
{tok::tk_var , "var" },
|
||||
{tok::tk_func , "func" },
|
||||
{tok::tk_brk , "break" },
|
||||
{tok::tk_cont , "continue"},
|
||||
{tok::tk_ret , "return" },
|
||||
{tok::tk_if , "if" },
|
||||
{tok::tk_elsif , "elsif" },
|
||||
{tok::tk_else , "else" },
|
||||
{tok::tk_nil , "nil" },
|
||||
{tok::tk_lcurve , "(" },
|
||||
{tok::tk_rcurve , ")" },
|
||||
{tok::tk_lbracket, "[" },
|
||||
{tok::tk_rbracket, "]" },
|
||||
{tok::tk_lbrace , "{" },
|
||||
{tok::tk_rbrace , "}" },
|
||||
{tok::tk_semi , ";" },
|
||||
{tok::tk_and , "and" },
|
||||
{tok::tk_or , "or" },
|
||||
{tok::tk_comma , "," },
|
||||
{tok::tk_dot , "." },
|
||||
{tok::tk_ellipsis, "..." },
|
||||
{tok::tk_quesmark, "?" },
|
||||
{tok::tk_quesques, "??" },
|
||||
{tok::tk_quesdot , "?." },
|
||||
{tok::tk_colon , ":" },
|
||||
{tok::tk_add , "+" },
|
||||
{tok::tk_sub , "-" },
|
||||
{tok::tk_mult , "*" },
|
||||
{tok::tk_div , "/" },
|
||||
{tok::tk_floater , "~" },
|
||||
{tok::tk_btand , "&" },
|
||||
{tok::tk_btor , "|" },
|
||||
{tok::tk_btxor , "^" },
|
||||
{tok::tk_not , "!" },
|
||||
{tok::tk_eq , "=" },
|
||||
{tok::tk_addeq , "+=" },
|
||||
{tok::tk_subeq , "-=" },
|
||||
{tok::tk_multeq , "*=" },
|
||||
{tok::tk_diveq , "/=" },
|
||||
{tok::tk_lnkeq , "~=" },
|
||||
{tok::tk_btandeq , "&=" },
|
||||
{tok::tk_btoreq , "|=" },
|
||||
{tok::tk_btxoreq , "^=" },
|
||||
{tok::tk_cmpeq , "==" },
|
||||
{tok::tk_neq , "!=" },
|
||||
{tok::tk_less , "<" },
|
||||
{tok::tk_leq , "<=" },
|
||||
{tok::tk_grt , ">" },
|
||||
{tok::tk_geq , ">=" }
|
||||
};
|
||||
|
||||
private:
|
||||
void die(const span&, const std::string&);
|
||||
void next();
|
||||
void match(tok, const char* info = nullptr);
|
||||
bool lookahead(tok);
|
||||
bool lookahead_expression();
|
||||
bool is_call(tok);
|
||||
bool check_comma(const tok*);
|
||||
bool check_tuple();
|
||||
bool check_func_end(expr*);
|
||||
bool check_in_curve_multi_definition();
|
||||
bool check_special_call();
|
||||
bool need_semi_check(expr*);
|
||||
void update_location(expr*);
|
||||
|
||||
private:
|
||||
use_stmt* use_stmt_gen();
|
||||
null_expr* null();
|
||||
nil_expr* nil();
|
||||
number_literal* num();
|
||||
string_literal* str();
|
||||
identifier* id();
|
||||
bool_literal* bools();
|
||||
vector_expr* vec();
|
||||
hash_expr* hash();
|
||||
hash_pair* pair();
|
||||
function* func();
|
||||
void params(function*);
|
||||
expr* lcurve_expr();
|
||||
expr* expression();
|
||||
code_block* expression_block();
|
||||
expr* calc();
|
||||
expr* bitwise_or();
|
||||
expr* bitwise_xor();
|
||||
expr* bitwise_and();
|
||||
expr* or_expr();
|
||||
expr* and_expr();
|
||||
expr* cmp_expr();
|
||||
expr* null_chain_expr();
|
||||
expr* additive_expr();
|
||||
expr* multive_expr();
|
||||
unary_operator* unary();
|
||||
expr* scalar();
|
||||
call* call_scalar();
|
||||
call_hash* callh();
|
||||
null_access* null_access_call();
|
||||
call_vector* callv();
|
||||
call_function* callf();
|
||||
slice_vector* subvec();
|
||||
expr* definition();
|
||||
multi_identifier* incurve_def();
|
||||
multi_identifier* outcurve_def();
|
||||
multi_identifier* multi_id();
|
||||
tuple_expr* multi_scalar();
|
||||
multi_assign* multi_assignment();
|
||||
expr* loop();
|
||||
while_expr* while_loop();
|
||||
for_expr* for_loop();
|
||||
forei_expr* forei_loop();
|
||||
iter_expr* iter_gen();
|
||||
condition_expr* cond();
|
||||
continue_expr* continue_expression();
|
||||
break_expr* break_expression();
|
||||
return_expr* return_expression();
|
||||
|
||||
public:
|
||||
code_block* tree() {return root;}
|
||||
|
||||
// swap root pointer with another pointer(maybe nullptr)
|
||||
code_block* swap(code_block* another) {
|
||||
auto res = root;
|
||||
root = another;
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
parse(): ptr(0), in_func_depth(0),
|
||||
in_loop_depth(0), toks(nullptr),
|
||||
root(nullptr) {}
|
||||
~parse() {delete root;}
|
||||
const error& compile(const lexer&);
|
||||
static void easter_egg();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,300 +1,281 @@
|
||||
#include "nasal_type.h"
|
||||
#include "util/util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
||||
if (!vec.elems.size() || vec.printed) {
|
||||
out << (vec.elems.size()? "[..]":"[]");
|
||||
return out;
|
||||
}
|
||||
vec.printed = true;
|
||||
usize iter = 0, size = vec.elems.size();
|
||||
out << "[";
|
||||
for (auto& i:vec.elems) {
|
||||
out << i << ",]"[(++iter)==size];
|
||||
}
|
||||
vec.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
var nas_hash::get_value(const std::string& key) {
|
||||
if (elems.count(key)) {
|
||||
return elems.at(key);
|
||||
}
|
||||
if (!elems.count("parents")) {
|
||||
return var::none();
|
||||
}
|
||||
|
||||
auto ret = var::none();
|
||||
auto& val = elems.at("parents");
|
||||
if (!val.is_vec()) {
|
||||
return ret;
|
||||
}
|
||||
for (auto& i : val.vec().elems) {
|
||||
if (i.is_hash()) {
|
||||
ret = i.hash().get_value(key);
|
||||
}
|
||||
if (!ret.is_none()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var* nas_hash::get_memory(const std::string& key) {
|
||||
if (elems.count(key)) {
|
||||
return &elems.at(key);
|
||||
}
|
||||
if (!elems.count("parents")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
var* addr = nullptr;
|
||||
var& val = elems.at("parents");
|
||||
if (!val.is_vec()) {
|
||||
return addr;
|
||||
}
|
||||
for (auto& i : val.vec().elems) {
|
||||
// recursively search key in `parents`
|
||||
if (i.is_hash()) {
|
||||
addr = i.hash().get_memory(key);
|
||||
}
|
||||
if (addr) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_hash& hash) {
|
||||
if (!hash.elems.size() || hash.printed) {
|
||||
out << (hash.elems.size()? "{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
|
||||
// mark print, to avoid infinite recursion
|
||||
hash.printed = true;
|
||||
|
||||
static const char* sep[] = {", ", "}"};
|
||||
usize iter = 0, size = hash.elems.size();
|
||||
out << "{";
|
||||
for (auto& i : hash.elems) {
|
||||
out << i.first << ": " << i.second << sep[(++iter)==size];
|
||||
}
|
||||
|
||||
// restore flag
|
||||
hash.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_func& func) {
|
||||
out << "func(";
|
||||
|
||||
std::vector<std::string> argument_list = {};
|
||||
argument_list.resize(func.keys.size());
|
||||
for (const auto& key : func.keys) {
|
||||
argument_list[key.second-1] = key.first;
|
||||
}
|
||||
|
||||
for (const auto& key : argument_list) {
|
||||
out << key;
|
||||
if (key != argument_list.back()) {
|
||||
out << ", ";
|
||||
}
|
||||
}
|
||||
if (func.dynamic_parameter_index>=0) {
|
||||
out << (argument_list.size()? ", ":"");
|
||||
out << func.dynamic_parameter_name << "...";
|
||||
}
|
||||
|
||||
out << ") {..}";
|
||||
return out;
|
||||
}
|
||||
|
||||
void nas_func::clear() {
|
||||
dynamic_parameter_index = -1;
|
||||
local.clear();
|
||||
upval.clear();
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
void nas_ghost::set(const std::string& ghost_type_name,
|
||||
destructor destructor_pointer,
|
||||
marker gc_marker_pointer,
|
||||
void* ghost_pointer) {
|
||||
type_name = ghost_type_name;
|
||||
destructor_function = destructor_pointer;
|
||||
gc_mark_function = gc_marker_pointer;
|
||||
pointer = ghost_pointer;
|
||||
}
|
||||
|
||||
void nas_ghost::clear() {
|
||||
// do nothing if pointer is null
|
||||
if (!pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do clear pointer if destructor function pointer is null
|
||||
if (!destructor_function) {
|
||||
type_name = "";
|
||||
pointer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// do destruction
|
||||
destructor_function(pointer);
|
||||
type_name = "";
|
||||
pointer = nullptr;
|
||||
destructor_function = nullptr;
|
||||
gc_mark_function = nullptr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) {
|
||||
out << "<" << ghost.get_ghost_name();
|
||||
out << "@0x" << std::hex << ghost.convert<u64>() << std::dec << ">";
|
||||
return out;
|
||||
}
|
||||
|
||||
void nas_co::clear() {
|
||||
if (!ctx.stack) {
|
||||
return;
|
||||
}
|
||||
for (u32 i = 0; i<VM_STACK_DEPTH; ++i) {
|
||||
ctx.stack[i] = var::nil();
|
||||
}
|
||||
|
||||
ctx.pc = 0;
|
||||
ctx.localr = nullptr;
|
||||
ctx.memr = nullptr;
|
||||
ctx.canary = ctx.stack+VM_STACK_DEPTH-1;
|
||||
ctx.top = ctx.stack;
|
||||
ctx.funcr = var::nil();
|
||||
ctx.upvalr = var::nil();
|
||||
|
||||
status = status::suspended;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const nas_co& co) {
|
||||
out << "<coroutine at 0x" << std::hex;
|
||||
out << reinterpret_cast<u64>(&co) << std::dec << ">";
|
||||
return out;
|
||||
}
|
||||
|
||||
var nas_map::get_value(const std::string& key) {
|
||||
if (mapper.count(key)) {
|
||||
return *mapper.at(key);
|
||||
}
|
||||
return var::none();
|
||||
}
|
||||
|
||||
var* nas_map::get_memory(const std::string& key) {
|
||||
if (mapper.count(key)) {
|
||||
return mapper.at(key);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_map& mp) {
|
||||
if (!mp.mapper.size() || mp.printed) {
|
||||
out << (mp.mapper.size()? "{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
|
||||
// mark print, to avoid infinite recursion
|
||||
mp.printed = true;
|
||||
|
||||
static const char* sep[] = {", ", "}"};
|
||||
usize iter = 0, size = mp.mapper.size();
|
||||
out << "{";
|
||||
for (auto& i : mp.mapper) {
|
||||
out << i.first << ": " << *i.second << sep[(++iter)==size];
|
||||
}
|
||||
|
||||
// restore flag
|
||||
mp.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
nas_val::nas_val(vm_type val_type) {
|
||||
mark = gc_status::collected;
|
||||
type = val_type;
|
||||
immutable = 0;
|
||||
switch(val_type) {
|
||||
case vm_type::vm_str: ptr.str = new std::string; break;
|
||||
case vm_type::vm_vec: ptr.vec = new nas_vec; break;
|
||||
case vm_type::vm_hash: ptr.hash = new nas_hash; break;
|
||||
case vm_type::vm_func: ptr.func = new nas_func; break;
|
||||
case vm_type::vm_upval: ptr.upval = new nas_upval; break;
|
||||
case vm_type::vm_ghost: ptr.obj = new nas_ghost; break;
|
||||
case vm_type::vm_co: ptr.co = new nas_co; break;
|
||||
case vm_type::vm_map: ptr.map = new nas_map; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
nas_val::~nas_val() {
|
||||
switch(type) {
|
||||
case vm_type::vm_str: delete ptr.str; break;
|
||||
case vm_type::vm_vec: delete ptr.vec; break;
|
||||
case vm_type::vm_hash: delete ptr.hash; break;
|
||||
case vm_type::vm_func: delete ptr.func; break;
|
||||
case vm_type::vm_upval: delete ptr.upval; break;
|
||||
case vm_type::vm_ghost: delete ptr.obj; break;
|
||||
case vm_type::vm_co: delete ptr.co; break;
|
||||
case vm_type::vm_map: delete ptr.map; break;
|
||||
default: break;
|
||||
}
|
||||
type = vm_type::vm_nil;
|
||||
}
|
||||
|
||||
void nas_val::clear() {
|
||||
switch(type) {
|
||||
case vm_type::vm_str: ptr.str->clear(); break;
|
||||
case vm_type::vm_vec: ptr.vec->elems.clear(); break;
|
||||
case vm_type::vm_hash: ptr.hash->elems.clear(); break;
|
||||
case vm_type::vm_func: ptr.func->clear(); break;
|
||||
case vm_type::vm_upval: ptr.upval->clear(); break;
|
||||
case vm_type::vm_ghost: ptr.obj->clear(); break;
|
||||
case vm_type::vm_co: ptr.co->clear(); break;
|
||||
case vm_type::vm_map: ptr.map->clear(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string var::to_str() {
|
||||
if (type==vm_type::vm_str) {
|
||||
return str();
|
||||
} else if (type==vm_type::vm_num) {
|
||||
auto tmp = std::to_string(num());
|
||||
tmp.erase(tmp.find_last_not_of('0') + 1, std::string::npos);
|
||||
tmp.erase(tmp.find_last_not_of('.') + 1, std::string::npos);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, var& ref) {
|
||||
switch(ref.type) {
|
||||
case vm_type::vm_none: out << "undefined"; break;
|
||||
case vm_type::vm_nil: out << "nil"; break;
|
||||
case vm_type::vm_num: out << ref.val.num; break;
|
||||
case vm_type::vm_str: out << ref.str(); break;
|
||||
case vm_type::vm_vec: out << ref.vec(); break;
|
||||
case vm_type::vm_hash: out << ref.hash(); break;
|
||||
case vm_type::vm_func: out << ref.func(); break;
|
||||
case vm_type::vm_ghost: out << ref.ghost(); break;
|
||||
case vm_type::vm_co: out << ref.co(); break;
|
||||
case vm_type::vm_map: out << ref.map(); break;
|
||||
default: break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "nasal_type.h"
|
||||
#include "util/util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_vec& vec) {
|
||||
if (!vec.elems.size() || vec.printed) {
|
||||
out << (vec.elems.size()? "[..]":"[]");
|
||||
return out;
|
||||
}
|
||||
vec.printed = true;
|
||||
usize iter = 0, size = vec.elems.size();
|
||||
out << "[";
|
||||
for (auto& i:vec.elems) {
|
||||
out << i << ",]"[(++iter)==size];
|
||||
}
|
||||
vec.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
var nas_hash::get_value(const std::string& key) {
|
||||
if (elems.count(key)) {
|
||||
return elems.at(key);
|
||||
}
|
||||
if (!elems.count("parents")) {
|
||||
return var::none();
|
||||
}
|
||||
|
||||
auto ret = var::none();
|
||||
auto& val = elems.at("parents");
|
||||
if (!val.is_vec()) {
|
||||
return ret;
|
||||
}
|
||||
for (auto& i : val.vec().elems) {
|
||||
if (i.is_hash()) {
|
||||
ret = i.hash().get_value(key);
|
||||
}
|
||||
if (!ret.is_none()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var* nas_hash::get_memory(const std::string& key) {
|
||||
if (elems.count(key)) {
|
||||
return &elems.at(key);
|
||||
}
|
||||
if (!elems.count("parents")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
var* addr = nullptr;
|
||||
var& val = elems.at("parents");
|
||||
if (!val.is_vec()) {
|
||||
return addr;
|
||||
}
|
||||
for (auto& i : val.vec().elems) {
|
||||
// recursively search key in `parents`
|
||||
if (i.is_hash()) {
|
||||
addr = i.hash().get_memory(key);
|
||||
}
|
||||
if (addr) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_hash& hash) {
|
||||
if (!hash.elems.size() || hash.printed) {
|
||||
out << (hash.elems.size()? "{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
|
||||
// mark print, to avoid infinite recursion
|
||||
hash.printed = true;
|
||||
|
||||
static const char* sep[] = {", ", "}"};
|
||||
usize iter = 0, size = hash.elems.size();
|
||||
out << "{";
|
||||
for (auto& i : hash.elems) {
|
||||
out << i.first << ": " << i.second << sep[(++iter)==size];
|
||||
}
|
||||
|
||||
// restore flag
|
||||
hash.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_func& func) {
|
||||
out << "func(";
|
||||
|
||||
std::vector<std::string> argument_list = {};
|
||||
argument_list.resize(func.keys.size());
|
||||
for (const auto& key : func.keys) {
|
||||
argument_list[key.second-1] = key.first;
|
||||
}
|
||||
|
||||
for (const auto& key : argument_list) {
|
||||
out << key;
|
||||
if (key != argument_list.back()) {
|
||||
out << ", ";
|
||||
}
|
||||
}
|
||||
if (func.dynamic_parameter_index>=0) {
|
||||
out << (argument_list.size()? ", ":"");
|
||||
out << func.dynamic_parameter_name << "...";
|
||||
}
|
||||
|
||||
out << ") {..}";
|
||||
return out;
|
||||
}
|
||||
|
||||
void nas_func::clear() {
|
||||
dynamic_parameter_index = -1;
|
||||
local.clear();
|
||||
upval.clear();
|
||||
keys.clear();
|
||||
}
|
||||
|
||||
void nas_ghost::set(const std::string& ghost_type_name,
|
||||
destructor destructor_pointer,
|
||||
marker gc_marker_pointer,
|
||||
void* ghost_pointer) {
|
||||
type_name = ghost_type_name;
|
||||
destructor_function = destructor_pointer;
|
||||
gc_mark_function = gc_marker_pointer;
|
||||
pointer = ghost_pointer;
|
||||
}
|
||||
|
||||
void nas_ghost::clear() {
|
||||
// do nothing if pointer is null
|
||||
if (!pointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do clear pointer if destructor function pointer is null
|
||||
if (!destructor_function) {
|
||||
type_name = "";
|
||||
pointer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// do destruction
|
||||
destructor_function(pointer);
|
||||
type_name = "";
|
||||
pointer = nullptr;
|
||||
destructor_function = nullptr;
|
||||
gc_mark_function = nullptr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const nas_ghost& ghost) {
|
||||
out << "<" << ghost.get_ghost_name();
|
||||
out << "@0x" << std::hex << ghost.convert<u64>() << std::dec << ">";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const nas_co& co) {
|
||||
out << "<coroutine at 0x" << std::hex;
|
||||
out << reinterpret_cast<u64>(&co) << std::dec << ">";
|
||||
return out;
|
||||
}
|
||||
|
||||
var nas_map::get_value(const std::string& key) {
|
||||
if (mapper.count(key)) {
|
||||
return *mapper.at(key);
|
||||
}
|
||||
return var::none();
|
||||
}
|
||||
|
||||
var* nas_map::get_memory(const std::string& key) {
|
||||
if (mapper.count(key)) {
|
||||
return mapper.at(key);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, nas_map& mp) {
|
||||
if (!mp.mapper.size() || mp.printed) {
|
||||
out << (mp.mapper.size()? "{..}":"{}");
|
||||
return out;
|
||||
}
|
||||
|
||||
// mark print, to avoid infinite recursion
|
||||
mp.printed = true;
|
||||
|
||||
static const char* sep[] = {", ", "}"};
|
||||
usize iter = 0, size = mp.mapper.size();
|
||||
out << "{";
|
||||
for (auto& i : mp.mapper) {
|
||||
out << i.first << ": " << *i.second << sep[(++iter)==size];
|
||||
}
|
||||
|
||||
// restore flag
|
||||
mp.printed = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
nas_val::nas_val(vm_type val_type) {
|
||||
mark = gc_status::collected;
|
||||
type = val_type;
|
||||
immutable = 0;
|
||||
switch(val_type) {
|
||||
case vm_type::vm_str: ptr.str = new std::string; break;
|
||||
case vm_type::vm_vec: ptr.vec = new nas_vec; break;
|
||||
case vm_type::vm_hash: ptr.hash = new nas_hash; break;
|
||||
case vm_type::vm_func: ptr.func = new nas_func; break;
|
||||
case vm_type::vm_upval: ptr.upval = new nas_upval; break;
|
||||
case vm_type::vm_ghost: ptr.obj = new nas_ghost; break;
|
||||
case vm_type::vm_co: ptr.co = new nas_co; break;
|
||||
case vm_type::vm_map: ptr.map = new nas_map; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
nas_val::~nas_val() {
|
||||
switch(type) {
|
||||
case vm_type::vm_str: delete ptr.str; break;
|
||||
case vm_type::vm_vec: delete ptr.vec; break;
|
||||
case vm_type::vm_hash: delete ptr.hash; break;
|
||||
case vm_type::vm_func: delete ptr.func; break;
|
||||
case vm_type::vm_upval: delete ptr.upval; break;
|
||||
case vm_type::vm_ghost: delete ptr.obj; break;
|
||||
case vm_type::vm_co: delete ptr.co; break;
|
||||
case vm_type::vm_map: delete ptr.map; break;
|
||||
default: break;
|
||||
}
|
||||
type = vm_type::vm_nil;
|
||||
}
|
||||
|
||||
void nas_val::clear() {
|
||||
switch(type) {
|
||||
case vm_type::vm_str: ptr.str->clear(); break;
|
||||
case vm_type::vm_vec: ptr.vec->elems.clear(); break;
|
||||
case vm_type::vm_hash: ptr.hash->elems.clear(); break;
|
||||
case vm_type::vm_func: ptr.func->clear(); break;
|
||||
case vm_type::vm_upval: ptr.upval->clear(); break;
|
||||
case vm_type::vm_ghost: ptr.obj->clear(); break;
|
||||
case vm_type::vm_co: ptr.co->clear(); break;
|
||||
case vm_type::vm_map: ptr.map->clear(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string var::to_str() {
|
||||
if (type==vm_type::vm_str) {
|
||||
return str();
|
||||
} else if (type==vm_type::vm_num) {
|
||||
auto tmp = std::to_string(num());
|
||||
tmp.erase(tmp.find_last_not_of('0') + 1, std::string::npos);
|
||||
tmp.erase(tmp.find_last_not_of('.') + 1, std::string::npos);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, var& ref) {
|
||||
switch(ref.type) {
|
||||
case vm_type::vm_none: out << "undefined"; break;
|
||||
case vm_type::vm_nil: out << "nil"; break;
|
||||
case vm_type::vm_num: out << ref.val.num; break;
|
||||
case vm_type::vm_str: out << ref.str(); break;
|
||||
case vm_type::vm_vec: out << ref.vec(); break;
|
||||
case vm_type::vm_hash: out << ref.hash(); break;
|
||||
case vm_type::vm_func: out << ref.func(); break;
|
||||
case vm_type::vm_ghost: out << ref.ghost(); break;
|
||||
case vm_type::vm_co: out << ref.co(); break;
|
||||
case vm_type::vm_map: out << ref.map(); break;
|
||||
default: break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
757
src/nasal_type.h
757
src/nasal_type.h
@@ -1,362 +1,397 @@
|
||||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "util/util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
enum class vm_type: u8 {
|
||||
/* none-gc object */
|
||||
vm_none = 0, // error type
|
||||
vm_cnt, // counter for forindex/foreach loop
|
||||
vm_addr, // var* address
|
||||
vm_ret, // return addres(program counter)
|
||||
vm_nil, // nil
|
||||
vm_num, // number
|
||||
|
||||
/* gc object */
|
||||
vm_str, // string
|
||||
vm_vec, // vector
|
||||
vm_hash, // hashmap(dict)
|
||||
vm_func, // function(lambda)
|
||||
vm_upval, // upvalue
|
||||
vm_ghost, // ghost type
|
||||
vm_co, // coroutine
|
||||
vm_map, // for globals and namespaces
|
||||
|
||||
/* mark type range */
|
||||
vm_type_size_max
|
||||
};
|
||||
|
||||
// size of gc object type
|
||||
const u32 GC_TYPE_SIZE =
|
||||
static_cast<u32>(vm_type::vm_type_size_max) -
|
||||
static_cast<u32>(vm_type::vm_str);
|
||||
|
||||
// basic types
|
||||
struct nas_vec; // vector
|
||||
struct nas_hash; // hashmap(dict)
|
||||
struct nas_func; // function(lambda)
|
||||
struct nas_upval; // upvalue
|
||||
struct nas_ghost; // objects
|
||||
struct nas_co; // coroutine
|
||||
struct nas_map; // mapper
|
||||
|
||||
// nas_val includes gc-managed types
|
||||
struct nas_val {
|
||||
enum class gc_status: u8 {
|
||||
uncollected = 0,
|
||||
collected,
|
||||
found
|
||||
};
|
||||
|
||||
gc_status mark;
|
||||
vm_type type; // value type
|
||||
u8 immutable; // used to mark if a string is immutable
|
||||
union elem {
|
||||
std::string* str;
|
||||
nas_vec* vec;
|
||||
nas_hash* hash;
|
||||
nas_func* func;
|
||||
nas_upval* upval;
|
||||
nas_ghost* obj;
|
||||
nas_co* co;
|
||||
nas_map* map;
|
||||
} ptr;
|
||||
|
||||
nas_val(vm_type);
|
||||
~nas_val();
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct var {
|
||||
public:
|
||||
vm_type type = vm_type::vm_none;
|
||||
union {
|
||||
u64 ret;
|
||||
i64 cnt;
|
||||
f64 num;
|
||||
var* addr;
|
||||
nas_val* gcobj;
|
||||
} val;
|
||||
|
||||
private:
|
||||
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, f64 n) { type = t; val.num = n; }
|
||||
var(vm_type t, var* p) { type = t; val.addr = p; }
|
||||
var(vm_type t, nas_val* p) { type = t; val.gcobj = p; }
|
||||
|
||||
public:
|
||||
var() = default;
|
||||
var(const var&) = default;
|
||||
bool operator==(const var& nr) const {
|
||||
return type == nr.type && val.gcobj == nr.val.gcobj;
|
||||
}
|
||||
bool operator!=(const var& nr) const {
|
||||
return type != nr.type || val.gcobj != nr.val.gcobj;
|
||||
}
|
||||
|
||||
public:
|
||||
// create new var object
|
||||
static var none() {
|
||||
return var(vm_type::vm_none, static_cast<u64>(0));
|
||||
}
|
||||
static var nil() {
|
||||
return var(vm_type::vm_nil, static_cast<u64>(0));
|
||||
}
|
||||
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:
|
||||
// get value
|
||||
var* addr() const { return val.addr; }
|
||||
u64 ret() const { return val.ret; }
|
||||
i64& cnt() { return val.cnt; }
|
||||
f64 num() const { return val.num; }
|
||||
|
||||
public:
|
||||
// get gc object
|
||||
std::string& str() { return *val.gcobj->ptr.str; }
|
||||
nas_vec& vec() { return *val.gcobj->ptr.vec; }
|
||||
nas_hash& hash() { return *val.gcobj->ptr.hash; }
|
||||
nas_func& func() { return *val.gcobj->ptr.func; }
|
||||
nas_upval& upval() { return *val.gcobj->ptr.upval; }
|
||||
nas_ghost& ghost() { return *val.gcobj->ptr.obj; }
|
||||
nas_co& co() { return *val.gcobj->ptr.co; }
|
||||
nas_map& map() { return *val.gcobj->ptr.map; }
|
||||
|
||||
|
||||
public:
|
||||
// get const gc object
|
||||
const std::string& str() const { return *val.gcobj->ptr.str; }
|
||||
const nas_vec& vec() const { return *val.gcobj->ptr.vec; }
|
||||
const nas_hash& hash() const { return *val.gcobj->ptr.hash; }
|
||||
const nas_func& func() const { return *val.gcobj->ptr.func; }
|
||||
const nas_upval& upval() const { return *val.gcobj->ptr.upval; }
|
||||
const nas_ghost& ghost() const { return *val.gcobj->ptr.obj; }
|
||||
const nas_co& co() const { return *val.gcobj->ptr.co; }
|
||||
const nas_map& map() const { return *val.gcobj->ptr.map; }
|
||||
|
||||
public:
|
||||
bool is_none() const { return type == vm_type::vm_none; }
|
||||
bool is_cnt() const { return type == vm_type::vm_cnt; }
|
||||
bool is_addr() const { return type == vm_type::vm_addr; }
|
||||
bool is_ret() const { return type == vm_type::vm_ret; }
|
||||
bool is_nil() const { return type == vm_type::vm_nil; }
|
||||
bool is_num() const { return type == vm_type::vm_num; }
|
||||
bool is_str() const { return type == vm_type::vm_str; }
|
||||
bool is_vec() const { return type == vm_type::vm_vec; }
|
||||
bool is_hash() const { return type == vm_type::vm_hash; }
|
||||
bool is_func() const { return type == vm_type::vm_func; }
|
||||
bool is_upval() const { return type == vm_type::vm_upval; }
|
||||
bool is_ghost() const { return type == vm_type::vm_ghost; }
|
||||
bool is_coroutine() const { return type == vm_type::vm_co; }
|
||||
bool is_map() const { return type == vm_type::vm_map; }
|
||||
|
||||
public:
|
||||
// convert to number
|
||||
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();
|
||||
inline bool object_check(const std::string&) const;
|
||||
friend std::ostream& operator<<(std::ostream&, var&);
|
||||
};
|
||||
|
||||
struct nas_vec {
|
||||
std::vector<var> elems;
|
||||
|
||||
// mark if this is printed, avoid stack overflow
|
||||
bool printed = false;
|
||||
|
||||
auto size() const { return elems.size(); }
|
||||
var 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* 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 {
|
||||
std::unordered_map<std::string, var> elems;
|
||||
|
||||
// mark if this is printed, avoid stack overflow
|
||||
bool printed = false;
|
||||
|
||||
auto size() const { return elems.size(); }
|
||||
var get_value(const std::string&);
|
||||
var* get_memory(const std::string&);
|
||||
friend std::ostream& operator<<(std::ostream&, nas_hash&);
|
||||
};
|
||||
|
||||
struct nas_func {
|
||||
i64 dynamic_parameter_index; // dynamic parameter name index in hash.
|
||||
u64 entry; // pc will set to entry-1 to call this function
|
||||
u32 parameter_size; // used to load default parameters to a new function
|
||||
u64 local_size; // used to expand memory space for local values on stack
|
||||
std::vector<var> local; // local scope with default value(var)
|
||||
std::vector<var> upval; // closure
|
||||
|
||||
// parameter table, u32 begins from 1
|
||||
std::unordered_map<std::string, u32> keys;
|
||||
|
||||
// dynamic parameter name
|
||||
std::string dynamic_parameter_name;
|
||||
|
||||
nas_func():
|
||||
dynamic_parameter_index(-1), entry(0),
|
||||
parameter_size(0), local_size(0),
|
||||
dynamic_parameter_name("") {}
|
||||
void clear();
|
||||
friend std::ostream& operator<<(std::ostream&, nas_func&);
|
||||
};
|
||||
|
||||
struct nas_upval {
|
||||
public:
|
||||
/* on stack, use these variables */
|
||||
bool on_stack;
|
||||
u64 size;
|
||||
var* stack_frame_offset;
|
||||
|
||||
/* not on stack, use this */
|
||||
std::vector<var> elems;
|
||||
|
||||
public:
|
||||
nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {}
|
||||
|
||||
var& operator[](usize n) {
|
||||
return on_stack? stack_frame_offset[n] : elems[n];
|
||||
}
|
||||
|
||||
void clear() {
|
||||
on_stack = true;
|
||||
elems.clear();
|
||||
size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct nas_ghost {
|
||||
private:
|
||||
using destructor = void (*)(void*);
|
||||
using marker = void (*)(void*, std::vector<var>*);
|
||||
|
||||
public:
|
||||
std::string type_name;
|
||||
destructor destructor_function;
|
||||
marker gc_mark_function;
|
||||
void* pointer;
|
||||
|
||||
public:
|
||||
nas_ghost():
|
||||
type_name(""), destructor_function(nullptr),
|
||||
gc_mark_function(nullptr), pointer(nullptr) {}
|
||||
~nas_ghost() { clear(); }
|
||||
void set(const std::string&, destructor, marker, void*);
|
||||
void clear();
|
||||
friend std::ostream& operator<<(std::ostream&, const nas_ghost&);
|
||||
|
||||
public:
|
||||
const auto& get_ghost_name() const { return type_name; }
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
T* get() { return static_cast<T*>(pointer); }
|
||||
template<typename T>
|
||||
T convert() const { return reinterpret_cast<T>(pointer); }
|
||||
};
|
||||
|
||||
struct context {
|
||||
u64 pc = 0;
|
||||
var* localr = nullptr;
|
||||
var* memr = nullptr;
|
||||
var funcr = var::nil();
|
||||
var upvalr = var::nil();
|
||||
var* canary = nullptr;
|
||||
var* stack = nullptr;
|
||||
var* top = nullptr;
|
||||
};
|
||||
|
||||
struct nas_co {
|
||||
enum class status:u32 {
|
||||
suspended,
|
||||
running,
|
||||
dead
|
||||
};
|
||||
|
||||
context ctx;
|
||||
status status;
|
||||
|
||||
nas_co() {
|
||||
ctx.stack = new var[VM_STACK_DEPTH];
|
||||
clear();
|
||||
}
|
||||
~nas_co() {
|
||||
delete[] ctx.stack;
|
||||
}
|
||||
void clear();
|
||||
friend std::ostream& operator<<(std::ostream&, const nas_co&);
|
||||
};
|
||||
|
||||
struct nas_map {
|
||||
bool printed = false;
|
||||
std::unordered_map<std::string, var*> mapper;
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
mapper.clear();
|
||||
}
|
||||
auto size() const { return mapper.size(); }
|
||||
|
||||
var get_value(const std::string&);
|
||||
var* get_memory(const std::string&);
|
||||
friend std::ostream& operator<<(std::ostream&, nas_map&);
|
||||
};
|
||||
|
||||
const var zero = var::num(0);
|
||||
const var one = var::num(1);
|
||||
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
|
||||
static var nas_err(const std::string& func, const std::string& info) {
|
||||
std::cerr << "[vm] " << func << ": " << info << "\n";
|
||||
return var::none();
|
||||
}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nasal.h"
|
||||
#include "util/util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace nasal {
|
||||
|
||||
enum class vm_type: u8 {
|
||||
/* none-gc object */
|
||||
vm_none = 0, // error type
|
||||
vm_cnt, // counter for forindex/foreach loop
|
||||
vm_addr, // var* address
|
||||
vm_ret, // return addres(program counter)
|
||||
vm_nil, // nil
|
||||
vm_num, // number
|
||||
|
||||
/* gc object */
|
||||
vm_str, // string
|
||||
vm_vec, // vector
|
||||
vm_hash, // hashmap(dict)
|
||||
vm_func, // function(lambda)
|
||||
vm_upval, // upvalue
|
||||
vm_ghost, // ghost type
|
||||
vm_co, // coroutine
|
||||
vm_map, // for globals and namespaces
|
||||
|
||||
/* mark type range */
|
||||
vm_type_size_max
|
||||
};
|
||||
|
||||
// size of gc object type
|
||||
const u32 GC_TYPE_SIZE =
|
||||
static_cast<u32>(vm_type::vm_type_size_max) -
|
||||
static_cast<u32>(vm_type::vm_str);
|
||||
|
||||
// basic types
|
||||
struct nas_vec; // vector
|
||||
struct nas_hash; // hashmap(dict)
|
||||
struct nas_func; // function(lambda)
|
||||
struct nas_upval; // upvalue
|
||||
struct nas_ghost; // objects
|
||||
struct nas_co; // coroutine
|
||||
struct nas_map; // mapper
|
||||
|
||||
// nas_val includes gc-managed types
|
||||
struct nas_val {
|
||||
enum class gc_status: u8 {
|
||||
uncollected = 0,
|
||||
collected,
|
||||
found
|
||||
};
|
||||
|
||||
gc_status mark;
|
||||
vm_type type; // value type
|
||||
u8 immutable; // used to mark if a string is immutable
|
||||
union elem {
|
||||
std::string* str;
|
||||
nas_vec* vec;
|
||||
nas_hash* hash;
|
||||
nas_func* func;
|
||||
nas_upval* upval;
|
||||
nas_ghost* obj;
|
||||
nas_co* co;
|
||||
nas_map* map;
|
||||
} ptr;
|
||||
|
||||
nas_val(vm_type);
|
||||
~nas_val();
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct var {
|
||||
public:
|
||||
vm_type type = vm_type::vm_none;
|
||||
union {
|
||||
u64 ret;
|
||||
i64 cnt;
|
||||
f64 num;
|
||||
var* addr;
|
||||
nas_val* gcobj;
|
||||
} val;
|
||||
|
||||
private:
|
||||
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, f64 n) { type = t; val.num = n; }
|
||||
var(vm_type t, var* p) { type = t; val.addr = p; }
|
||||
var(vm_type t, nas_val* p) { type = t; val.gcobj = p; }
|
||||
|
||||
public:
|
||||
var() = default;
|
||||
var(const var&) = default;
|
||||
bool operator==(const var& nr) const {
|
||||
return type == nr.type && val.gcobj == nr.val.gcobj;
|
||||
}
|
||||
bool operator!=(const var& nr) const {
|
||||
return type != nr.type || val.gcobj != nr.val.gcobj;
|
||||
}
|
||||
|
||||
public:
|
||||
// create new var object
|
||||
static var none() {
|
||||
return var(vm_type::vm_none, static_cast<u64>(0));
|
||||
}
|
||||
static var nil() {
|
||||
return var(vm_type::vm_nil, static_cast<u64>(0));
|
||||
}
|
||||
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:
|
||||
// get value
|
||||
var* addr() const { return val.addr; }
|
||||
u64 ret() const { return val.ret; }
|
||||
i64& cnt() { return val.cnt; }
|
||||
f64 num() const { return val.num; }
|
||||
|
||||
public:
|
||||
// get gc object
|
||||
std::string& str() { return *val.gcobj->ptr.str; }
|
||||
nas_vec& vec() { return *val.gcobj->ptr.vec; }
|
||||
nas_hash& hash() { return *val.gcobj->ptr.hash; }
|
||||
nas_func& func() { return *val.gcobj->ptr.func; }
|
||||
nas_upval& upval() { return *val.gcobj->ptr.upval; }
|
||||
nas_ghost& ghost() { return *val.gcobj->ptr.obj; }
|
||||
nas_co& co() { return *val.gcobj->ptr.co; }
|
||||
nas_map& map() { return *val.gcobj->ptr.map; }
|
||||
|
||||
public:
|
||||
// get const gc object
|
||||
const std::string& str() const { return *val.gcobj->ptr.str; }
|
||||
const nas_vec& vec() const { return *val.gcobj->ptr.vec; }
|
||||
const nas_hash& hash() const { return *val.gcobj->ptr.hash; }
|
||||
const nas_func& func() const { return *val.gcobj->ptr.func; }
|
||||
const nas_upval& upval() const { return *val.gcobj->ptr.upval; }
|
||||
const nas_ghost& ghost() const { return *val.gcobj->ptr.obj; }
|
||||
const nas_co& co() const { return *val.gcobj->ptr.co; }
|
||||
const nas_map& map() const { return *val.gcobj->ptr.map; }
|
||||
|
||||
public:
|
||||
bool is_none() const { return type == vm_type::vm_none; }
|
||||
bool is_cnt() const { return type == vm_type::vm_cnt; }
|
||||
bool is_addr() const { return type == vm_type::vm_addr; }
|
||||
bool is_ret() const { return type == vm_type::vm_ret; }
|
||||
bool is_nil() const { return type == vm_type::vm_nil; }
|
||||
bool is_num() const { return type == vm_type::vm_num; }
|
||||
bool is_str() const { return type == vm_type::vm_str; }
|
||||
bool is_vec() const { return type == vm_type::vm_vec; }
|
||||
bool is_hash() const { return type == vm_type::vm_hash; }
|
||||
bool is_func() const { return type == vm_type::vm_func; }
|
||||
bool is_upval() const { return type == vm_type::vm_upval; }
|
||||
bool is_ghost() const { return type == vm_type::vm_ghost; }
|
||||
bool is_coroutine() const { return type == vm_type::vm_co; }
|
||||
bool is_map() const { return type == vm_type::vm_map; }
|
||||
|
||||
public:
|
||||
// convert to number
|
||||
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();
|
||||
inline bool object_check(const std::string&) const;
|
||||
friend std::ostream& operator<<(std::ostream&, var&);
|
||||
};
|
||||
|
||||
struct nas_vec {
|
||||
std::vector<var> elems;
|
||||
|
||||
// mark if this is printed, avoid stack overflow
|
||||
bool printed = false;
|
||||
|
||||
auto size() const { return elems.size(); }
|
||||
var 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* 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 {
|
||||
std::unordered_map<std::string, var> elems;
|
||||
|
||||
// mark if this is printed, avoid stack overflow
|
||||
bool printed = false;
|
||||
|
||||
auto size() const { return elems.size(); }
|
||||
var get_value(const std::string&);
|
||||
var* get_memory(const std::string&);
|
||||
friend std::ostream& operator<<(std::ostream&, nas_hash&);
|
||||
};
|
||||
|
||||
struct nas_func {
|
||||
i64 dynamic_parameter_index; // dynamic parameter name index in hash.
|
||||
u64 entry; // pc will set to entry-1 to call this function
|
||||
u32 parameter_size; // used to load default parameters to a new function
|
||||
u64 local_size; // used to expand memory space for local values on stack
|
||||
std::vector<var> local; // local scope with default value(var)
|
||||
std::vector<var> upval; // closure
|
||||
|
||||
// parameter table, u32 begins from 1
|
||||
std::unordered_map<std::string, u32> keys;
|
||||
|
||||
// dynamic parameter name
|
||||
std::string dynamic_parameter_name;
|
||||
|
||||
nas_func():
|
||||
dynamic_parameter_index(-1), entry(0),
|
||||
parameter_size(0), local_size(0),
|
||||
dynamic_parameter_name("") {}
|
||||
void clear();
|
||||
friend std::ostream& operator<<(std::ostream&, nas_func&);
|
||||
};
|
||||
|
||||
struct nas_upval {
|
||||
public:
|
||||
/* on stack, use these variables */
|
||||
bool on_stack;
|
||||
u64 size;
|
||||
var* stack_frame_offset;
|
||||
|
||||
/* not on stack, use this */
|
||||
std::vector<var> elems;
|
||||
|
||||
public:
|
||||
nas_upval(): on_stack(true), size(0), stack_frame_offset(nullptr) {}
|
||||
|
||||
var& operator[](usize n) {
|
||||
return on_stack? stack_frame_offset[n] : elems[n];
|
||||
}
|
||||
|
||||
void clear() {
|
||||
on_stack = true;
|
||||
elems.clear();
|
||||
size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct nas_ghost {
|
||||
private:
|
||||
using destructor = void (*)(void*);
|
||||
using marker = void (*)(void*, std::vector<var>*);
|
||||
|
||||
public:
|
||||
std::string type_name;
|
||||
destructor destructor_function;
|
||||
marker gc_mark_function;
|
||||
void* pointer;
|
||||
|
||||
public:
|
||||
nas_ghost():
|
||||
type_name(""), destructor_function(nullptr),
|
||||
gc_mark_function(nullptr), pointer(nullptr) {}
|
||||
~nas_ghost() { clear(); }
|
||||
void set(const std::string&, destructor, marker, void*);
|
||||
void clear();
|
||||
friend std::ostream& operator<<(std::ostream&, const nas_ghost&);
|
||||
|
||||
public:
|
||||
const auto& get_ghost_name() const { return type_name; }
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
T* get() { return static_cast<T*>(pointer); }
|
||||
template<typename T>
|
||||
T convert() const { return reinterpret_cast<T>(pointer); }
|
||||
};
|
||||
|
||||
struct callsite {
|
||||
var caller;
|
||||
u64 file_index = 0;
|
||||
u64 line = 0;
|
||||
};
|
||||
|
||||
struct context {
|
||||
u64 pc = 0;
|
||||
var* localr = nullptr;
|
||||
var* memr = nullptr;
|
||||
var funcr = var::nil();
|
||||
var upvalr = var::nil();
|
||||
var* canary = nullptr;
|
||||
|
||||
var* stack = nullptr;
|
||||
var* top = nullptr;
|
||||
|
||||
callsite* func_stack = nullptr;
|
||||
callsite* func_top = nullptr;
|
||||
|
||||
const std::string* files = nullptr;
|
||||
|
||||
void ctor() {
|
||||
stack = new var[VM_STACK_DEPTH];
|
||||
func_stack = new callsite[VM_STACK_DEPTH];
|
||||
}
|
||||
void dtor() {
|
||||
delete[] stack;
|
||||
delete[] func_stack;
|
||||
}
|
||||
void clear() {
|
||||
/* set canary and program counter */
|
||||
pc = 0;
|
||||
localr = nullptr;
|
||||
memr = nullptr;
|
||||
funcr = var::nil();
|
||||
upvalr = var::nil();
|
||||
|
||||
/* set canary = stack[VM_STACK_DEPTH-1] */
|
||||
canary = stack + VM_STACK_DEPTH - 1;
|
||||
|
||||
/* nothing is on stack */
|
||||
top = stack;
|
||||
func_top = func_stack - 1;
|
||||
|
||||
/* clear main stack */
|
||||
for (u32 i = 0; i < VM_STACK_DEPTH; ++i) {
|
||||
stack[i] = var::nil();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct nas_co {
|
||||
enum class status:u32 {
|
||||
suspended,
|
||||
running,
|
||||
dead
|
||||
};
|
||||
|
||||
context ctx;
|
||||
status status;
|
||||
|
||||
nas_co() { ctx.ctor(); }
|
||||
~nas_co() { ctx.dtor(); }
|
||||
void clear() { ctx.clear(); status = status::suspended; }
|
||||
friend std::ostream& operator<<(std::ostream&, const nas_co&);
|
||||
};
|
||||
|
||||
struct nas_map {
|
||||
bool printed = false;
|
||||
std::unordered_map<std::string, var*> mapper;
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
mapper.clear();
|
||||
}
|
||||
auto size() const { return mapper.size(); }
|
||||
|
||||
var get_value(const std::string&);
|
||||
var* get_memory(const std::string&);
|
||||
friend std::ostream& operator<<(std::ostream&, nas_map&);
|
||||
};
|
||||
|
||||
const var zero = var::num(0);
|
||||
const var one = var::num(1);
|
||||
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
|
||||
static var nas_err(const std::string& func, const std::string& info) {
|
||||
std::cerr << "[vm] " << func << ": " << info << "\n";
|
||||
return var::none();
|
||||
}
|
||||
|
||||
}
|
||||
1655
src/nasal_vm.cpp
1655
src/nasal_vm.cpp
File diff suppressed because it is too large
Load Diff
@@ -287,11 +287,11 @@ public:
|
||||
|
||||
/* constructor of vm instance */
|
||||
vm() {
|
||||
ctx.stack = new var[VM_STACK_DEPTH];
|
||||
ctx.ctor();
|
||||
global = new var[VM_STACK_DEPTH];
|
||||
}
|
||||
~vm() {
|
||||
delete[] ctx.stack;
|
||||
ctx.dtor();
|
||||
delete[] global;
|
||||
}
|
||||
|
||||
@@ -900,6 +900,11 @@ inline void vm::o_callfv() {
|
||||
var tmp = local[-1];
|
||||
local[-1] = ctx.funcr;
|
||||
ctx.funcr = tmp;
|
||||
(++ctx.func_top)[0] = {
|
||||
tmp,
|
||||
bytecode[ctx.pc].fidx,
|
||||
bytecode[ctx.pc].line
|
||||
};
|
||||
|
||||
// top-argc+lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
||||
if (ctx.top-argc+func.local_size+3>=ctx.canary) {
|
||||
@@ -969,6 +974,11 @@ inline void vm::o_callfh() {
|
||||
var tmp = ctx.top[-1];
|
||||
ctx.top[-1] = ctx.funcr;
|
||||
ctx.funcr = tmp;
|
||||
(++ctx.func_top)[0] = {
|
||||
tmp,
|
||||
bytecode[ctx.pc].fidx,
|
||||
bytecode[ctx.pc].line
|
||||
};
|
||||
|
||||
// top -1(hash) +lsize(local) +1(old pc) +1(old localr) +1(old upvalr)
|
||||
if (ctx.top+func.local_size+2>= ctx.canary) {
|
||||
@@ -1011,6 +1021,9 @@ inline void vm::o_callb() {
|
||||
// this code is written for coroutine
|
||||
(++ctx.top)[0] = nil;
|
||||
|
||||
// set file list into ctx
|
||||
ctx.files = files;
|
||||
|
||||
// if running a native function about coroutine
|
||||
// (top) will be set to another context.top, instead of main_context.top
|
||||
auto function_pointer = native_function[imm[ctx.pc]].func;
|
||||
@@ -1212,6 +1225,7 @@ inline void vm::o_ret() {
|
||||
ctx.top = local-1;
|
||||
ctx.funcr = ctx.top[0];
|
||||
ctx.top[0] = ret; // rewrite func with returned value
|
||||
ctx.func_top--;
|
||||
|
||||
// synchronize upvalue
|
||||
if (up.is_upval()) {
|
||||
|
||||
@@ -79,7 +79,7 @@ void* nasal_init() {
|
||||
|
||||
void nasal_cleanup(void* context) {
|
||||
auto* ctx = static_cast<NasalContext*>(context);
|
||||
ctx->vm_instance.reset();
|
||||
ctx->vm_instance.reset();
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
@@ -92,15 +92,15 @@ void nasal_set_timeout(void* context, int seconds) {
|
||||
const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
using clk = std::chrono::high_resolution_clock;
|
||||
const auto den = clk::duration::period::den;
|
||||
|
||||
|
||||
auto* ctx = static_cast<NasalContext*>(context);
|
||||
|
||||
|
||||
try {
|
||||
nasal::lexer lex;
|
||||
nasal::parse parse;
|
||||
nasal::linker ld;
|
||||
nasal::codegen gen;
|
||||
|
||||
|
||||
// Create a unique temporary file
|
||||
char temp_filename[256];
|
||||
snprintf(temp_filename, sizeof(temp_filename), "/tmp/nasal_eval_%ld_XXXXXX", std::time(nullptr));
|
||||
@@ -118,7 +118,7 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
temp_file << code;
|
||||
temp_file.close();
|
||||
close(fd);
|
||||
|
||||
|
||||
// Capture stdout and stderr
|
||||
std::stringstream output;
|
||||
std::stringstream error_output;
|
||||
@@ -151,7 +151,7 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
}
|
||||
auto opt = std::make_unique<nasal::optimizer>();
|
||||
opt->do_optimization(parse.tree());
|
||||
|
||||
|
||||
if (gen.compile(parse, ld, false, true).geterr()) {
|
||||
ctx->last_error = error_output.str();
|
||||
std::cout.rdbuf(old_cout);
|
||||
@@ -161,7 +161,7 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
}
|
||||
|
||||
const auto start = show_time ? clk::now() : clk::time_point();
|
||||
|
||||
|
||||
// Create a future for the VM execution
|
||||
auto future = std::async(std::launch::async, [&]() {
|
||||
// Wrap VM execution in try/catch
|
||||
@@ -181,15 +181,15 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
if (status == std::future_status::timeout) {
|
||||
ctx->interrupted.store(true);
|
||||
std::remove(temp_filename);
|
||||
throw std::runtime_error("Execution timed out after " +
|
||||
throw std::runtime_error("Execution timed out after " +
|
||||
std::to_string(ctx->timeout.count()) + " seconds");
|
||||
}
|
||||
|
||||
const auto end = show_time ? clk::now() : clk::time_point();
|
||||
|
||||
|
||||
std::cout.rdbuf(old_cout);
|
||||
std::cerr.rdbuf(old_cerr);
|
||||
|
||||
|
||||
std::stringstream result;
|
||||
result << output.str();
|
||||
if (!error_output.str().empty()) {
|
||||
@@ -198,15 +198,15 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||
if (result.str().empty()) {
|
||||
result << "Execution completed successfully.\n";
|
||||
}
|
||||
|
||||
|
||||
if (show_time) {
|
||||
double execution_time = static_cast<double>((end-start).count())/den;
|
||||
result << "\nExecution time: " << execution_time << "s";
|
||||
}
|
||||
|
||||
|
||||
ctx->last_result = result.str();
|
||||
std::remove(temp_filename);
|
||||
|
||||
|
||||
return ctx->last_result.c_str();
|
||||
} catch (const std::exception& e) {
|
||||
ctx->last_error = e.what();
|
||||
@@ -221,20 +221,20 @@ const char* nasal_get_error(void* context) {
|
||||
|
||||
void* nasal_repl_init() {
|
||||
auto* ctx = new WebReplContext();
|
||||
|
||||
|
||||
try {
|
||||
// Initialize environment silently
|
||||
nasal::repl::info::instance()->in_repl_mode = true;
|
||||
ctx->repl_instance->get_runtime().set_repl_mode_flag(true);
|
||||
ctx->repl_instance->get_runtime().set_detail_report_info(false);
|
||||
|
||||
|
||||
// Run initial setup
|
||||
ctx->repl_instance->set_source({});
|
||||
if (!ctx->repl_instance->run()) {
|
||||
ctx->last_error = "Failed to initialize REPL environment";
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
// Enable output after initialization
|
||||
ctx->allow_output = true;
|
||||
ctx->repl_instance->get_runtime().set_allow_repl_output_flag(true);
|
||||
@@ -242,7 +242,7 @@ void* nasal_repl_init() {
|
||||
} catch (const std::exception& e) {
|
||||
ctx->last_error = std::string("Initialization error: ") + e.what();
|
||||
}
|
||||
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ void nasal_repl_set_timeout(void* context, int seconds) {
|
||||
|
||||
const char* nasal_repl_eval(void* context, const char* line) {
|
||||
auto* ctx = static_cast<WebReplContext*>(context);
|
||||
|
||||
|
||||
if (!ctx->initialized) {
|
||||
ctx->last_error = "REPL not properly initialized";
|
||||
return ctx->last_error.c_str();
|
||||
@@ -266,7 +266,7 @@ const char* nasal_repl_eval(void* context, const char* line) {
|
||||
|
||||
try {
|
||||
std::string input_line(line);
|
||||
|
||||
|
||||
// Handle empty input
|
||||
if (input_line.empty()) {
|
||||
ctx->last_result = "";
|
||||
@@ -276,7 +276,7 @@ const char* nasal_repl_eval(void* context, const char* line) {
|
||||
// Handle REPL commands
|
||||
if (input_line[0] == '.') {
|
||||
if (input_line == ".help" || input_line == ".h") {
|
||||
ctx->last_result =
|
||||
ctx->last_result =
|
||||
"Nasal REPL commands:\n"
|
||||
" .help .h show this help message\n"
|
||||
" .clear .c clear screen\n"
|
||||
@@ -296,8 +296,8 @@ const char* nasal_repl_eval(void* context, const char* line) {
|
||||
}
|
||||
else if (input_line == ".source" || input_line == ".s") {
|
||||
// Return accumulated source
|
||||
ctx->last_result = ctx->source.empty() ?
|
||||
"(no source)" :
|
||||
ctx->last_result = ctx->source.empty() ?
|
||||
"(no source)" :
|
||||
join_string(ctx->source, "\n");
|
||||
return ctx->last_result.c_str();
|
||||
}
|
||||
@@ -328,20 +328,20 @@ const char* nasal_repl_eval(void* context, const char* line) {
|
||||
|
||||
// Wait for completion or timeout
|
||||
auto status = future.wait_for(ctx->timeout);
|
||||
|
||||
|
||||
// Restore output streams first
|
||||
std::cout.rdbuf(old_cout);
|
||||
std::cerr.rdbuf(old_cerr);
|
||||
|
||||
if (status == std::future_status::timeout) {
|
||||
ctx->source.pop_back(); // Remove the line that caused timeout
|
||||
|
||||
|
||||
// Reset the REPL instance state
|
||||
ctx->repl_instance->get_runtime().set_repl_mode_flag(true);
|
||||
ctx->repl_instance->get_runtime().set_allow_repl_output_flag(true);
|
||||
ctx->repl_instance->set_source(ctx->source);
|
||||
|
||||
throw std::runtime_error("Execution timed out after " +
|
||||
|
||||
throw std::runtime_error("Execution timed out after " +
|
||||
std::to_string(ctx->timeout.count()) + " seconds");
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ const char* nasal_repl_eval(void* context, const char* line) {
|
||||
|
||||
int nasal_repl_is_complete(void* context, const char* line) {
|
||||
auto* ctx = static_cast<WebReplContext*>(context);
|
||||
|
||||
|
||||
if (!ctx->initialized) {
|
||||
return -1; // Error state
|
||||
}
|
||||
@@ -392,8 +392,8 @@ int nasal_repl_is_complete(void* context, const char* line) {
|
||||
|
||||
// Add this function to expose version info
|
||||
const char* nasal_repl_get_version() {
|
||||
static std::string version_info =
|
||||
std::string("version ") + __nasver__ +
|
||||
static std::string version_info =
|
||||
std::string("version ") + __nasver__ +
|
||||
" (" + __DATE__ + " " + __TIME__ + ")";
|
||||
return version_info.c_str();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ NASAL_EXPORT void nasal_set_timeout(void* context, int seconds);
|
||||
NASAL_EXPORT const char* nasal_eval(void* context, const char* code, int show_time);
|
||||
NASAL_EXPORT const char* nasal_get_error(void* context);
|
||||
|
||||
// REPL
|
||||
// REPL
|
||||
NASAL_EXPORT void* nasal_repl_init();
|
||||
NASAL_EXPORT void nasal_repl_cleanup(void* repl_context);
|
||||
NASAL_EXPORT void nasal_repl_set_timeout(void* repl_context, int seconds);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -69,6 +69,8 @@ var builtin_platform(context*, gc*);
|
||||
var builtin_arch(context*, gc*);
|
||||
var builtin_version(context*, gc*);
|
||||
|
||||
var builtin_caller(context*, gc*);
|
||||
|
||||
// md5 related functions
|
||||
std::string tohex(u32);
|
||||
std::string md5(const std::string&);
|
||||
|
||||
@@ -110,7 +110,7 @@ var builtin_dlopen(context* ctx, gc* ngc) {
|
||||
dlname.c_str(), RTLD_LOCAL|RTLD_LAZY
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
// check library pointer and insert into returned hashmap
|
||||
if (!dynamic_library_pointer) {
|
||||
return nas_err("dylib::dlopen",
|
||||
|
||||
@@ -247,7 +247,7 @@ void json::match(json_token_type type) {
|
||||
|
||||
void json::vector_member(nas_vec& vec, gc* ngc) {
|
||||
if (this_token.type==json_token_type::tok_lbrace) {
|
||||
vec.elems.push_back(hash_object_generate(ngc));
|
||||
vec.elems.push_back(hash_object_generate(ngc));
|
||||
} else if (this_token.type==json_token_type::tok_lbrkt) {
|
||||
vec.elems.push_back(vector_object_generate(ngc));
|
||||
} else if (this_token.type==json_token_type::tok_str) {
|
||||
@@ -285,7 +285,7 @@ void json::hash_member(nas_hash& hash, gc* ngc) {
|
||||
}
|
||||
match(json_token_type::tok_colon);
|
||||
if (this_token.type==json_token_type::tok_lbrace) {
|
||||
hash.elems.insert({name, hash_object_generate(ngc)});
|
||||
hash.elems.insert({name, hash_object_generate(ngc)});
|
||||
} else if (this_token.type==json_token_type::tok_lbrkt) {
|
||||
hash.elems.insert({name, vector_object_generate(ngc)});
|
||||
} else if (this_token.type==json_token_type::tok_str ||
|
||||
|
||||
@@ -172,7 +172,7 @@ var builtin_subprocess_active(context* ctx, gc* ngc) {
|
||||
// this means the child process is returned
|
||||
if (result==pid) {
|
||||
obj.ghost().get<subprocess>()->status = status;
|
||||
}
|
||||
}
|
||||
|
||||
return result==0? one:zero;
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "nasal_ast.h"
|
||||
#include "ast_visitor.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/ast_visitor.h"
|
||||
|
||||
namespace nasal {
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ void repl::execute() {
|
||||
std::cout << "\", input \".help\" for help\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
source.push_back(line);
|
||||
if (!check_need_more_input()) {
|
||||
source.pop_back();
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
// set empty history
|
||||
command_history = {""};
|
||||
}
|
||||
|
||||
|
||||
// Make these methods public for web REPL
|
||||
bool run();
|
||||
void execute();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "nasal_ast.h"
|
||||
#include "ast_visitor.h"
|
||||
#include "ast/ast.h"
|
||||
#include "ast/ast_visitor.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
@@ -385,7 +385,8 @@ var call = func(function, args = nil, _me = nil, locals = nil, error = nil) {
|
||||
}
|
||||
|
||||
var caller = func(level = 1) {
|
||||
die("this runtime does not support caller");
|
||||
# TODO: caller should return [scope, func, call location file, call location line]
|
||||
return __caller(level);
|
||||
}
|
||||
|
||||
var closure = func(function, level = 1) {
|
||||
@@ -415,4 +416,4 @@ var fgcommand = func(cmd, node=nil) {
|
||||
# elsif (ishash(node)) node = props.Node.new(node)._g;
|
||||
# _fgcommand(cmd, node);
|
||||
println("in progress, not supported yet.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ var sgn = func(x) {
|
||||
|
||||
# floor will get the integral number of input argument
|
||||
# which is less than or equal to this argument.
|
||||
# this is basic native function in old nasal,
|
||||
# this is basic native function in old nasal,
|
||||
# but we think it should have a copy in math module.
|
||||
var floor = func(x) {
|
||||
return __floor(x);
|
||||
|
||||
@@ -187,7 +187,7 @@ var Node = {
|
||||
setBoolValue : func _setBoolValue(me._g, arg),
|
||||
toggleBoolValue: func _toggleBoolValue(me._g, arg),
|
||||
setDoubleValue : func _setDoubleValue(me._g, arg),
|
||||
# adjustValue works like setDoubleValue but adds the argument to the
|
||||
# adjustValue works like setDoubleValue but adds the argument to the
|
||||
# current value of the node
|
||||
adjustValue : func _adjustValue(me._g, arg),
|
||||
unalias : func _unalias(me._g, arg),
|
||||
@@ -237,7 +237,7 @@ var Node = {
|
||||
}
|
||||
return p;
|
||||
},
|
||||
|
||||
|
||||
# add n to int property, do nothing, if prop type is not int
|
||||
# n will be integer and defaults to 1
|
||||
increment: func(n = 1) {
|
||||
@@ -251,7 +251,7 @@ var Node = {
|
||||
return nil;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
# sub n from int property, do nothing, if prop type is not int
|
||||
# n will be integer and defaults to 1
|
||||
decrement: func(n = 1) {
|
||||
@@ -264,10 +264,10 @@ var Node = {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
# checks if a string can be used as a prop name
|
||||
# returns 0 (invalid) or 1 (valid)
|
||||
# as string operations are expensive, use this only when necessary,
|
||||
# as string operations are expensive, use this only when necessary,
|
||||
# especially do not use in update loops
|
||||
isValidPropName: func(s) {
|
||||
if (!size(s)) return 0;
|
||||
@@ -281,7 +281,7 @@ var Node = {
|
||||
},
|
||||
|
||||
# replaces any invalid char by "_"
|
||||
# as string operations are expensive, use this only when necessary,
|
||||
# as string operations are expensive, use this only when necessary,
|
||||
# especially do not use in update loops
|
||||
makeValidPropName: func(s) {
|
||||
if (!size(s)) return nil;
|
||||
@@ -293,7 +293,7 @@ var Node = {
|
||||
rv ~= (_ispropname(s[i])) ? chr(s[i]) : "_";
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
##
|
||||
@@ -393,8 +393,8 @@ var dump = func {
|
||||
var copy = func(src, dest, attr = 0) {
|
||||
var sp = src.getPath() or "";
|
||||
var dp = dest.getPath() or "";
|
||||
|
||||
# sp and dp may be equal but on different trees!
|
||||
|
||||
# sp and dp may be equal but on different trees!
|
||||
# check if dest is sub node of source
|
||||
sp = split("/", sp);
|
||||
dp = split("/", dp);
|
||||
@@ -402,7 +402,7 @@ var copy = func(src, dest, attr = 0) {
|
||||
sp = subvec(sp, 1);
|
||||
dp = subvec(dp, 1);
|
||||
}
|
||||
|
||||
|
||||
foreach(var c; src.getChildren()) {
|
||||
var name = c.getName();
|
||||
var i = c.getIndex();
|
||||
|
||||
@@ -25,32 +25,32 @@ func {
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldd != i) { print("Ack!\n"); return; }
|
||||
|
||||
|
||||
if (obj.fielda != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldb != i) { print("Ack!\n"); return; }
|
||||
if (obj.fieldc != i) { print("Ack!\n"); return; }
|
||||
@@ -69,7 +69,7 @@ print("sin(32) = ", math.sin(angle), "\n");
|
||||
print("cos(32) = ", math.cos(angle), "\n");
|
||||
print("s^2 + c^s = ",
|
||||
math.sin(angle)*math.sin(angle)+math.cos(angle)*math.cos(angle), "\n");
|
||||
|
||||
|
||||
func {for (var j=0; j<10; j=j+1) {
|
||||
print(j, "/10\n");
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ var road_check_func = func() {
|
||||
props.getNode("/", 1).setValue("/controls/flight/rudder",Kp*error*error+Ki*intergral+Kd*derivative);
|
||||
else
|
||||
props.getNode("/", 1).setValue("/controls/flight/rudder",0);
|
||||
|
||||
|
||||
# for simulation test, in fg these three lines are deleted
|
||||
println(" rudder :",props.getNode("/controls/flight/rudder",1).getValue());
|
||||
println(" dt :",dt,'\tintergral :',intergral,'\tderivative :',derivative);
|
||||
|
||||
24
test/caller.nas
Normal file
24
test/caller.nas
Normal file
@@ -0,0 +1,24 @@
|
||||
var a = func(x, y, z) {
|
||||
for (var i = 0; i < 20; i += 1) {
|
||||
var cl = caller(i);
|
||||
if (cl == nil) {
|
||||
return;
|
||||
}
|
||||
print("[", i, "]\t", cl[1], "\t -> called from ", cl[2], ":", cl[3], "\n");
|
||||
}
|
||||
}
|
||||
|
||||
var b = func(x, y) {
|
||||
a(1, 2, 3);
|
||||
}
|
||||
|
||||
var c = func(x) b(1, 2);
|
||||
var d = func c(1);
|
||||
var e = func d();
|
||||
var f = func e();
|
||||
var g = func f();
|
||||
var h = func g();
|
||||
var i = func h();
|
||||
var j = func i();
|
||||
|
||||
j();
|
||||
@@ -109,7 +109,7 @@ for (var t = 0; t < 10; t += 1) {
|
||||
counter += 1;
|
||||
for (var i = 0; i < t + 1; i += 1)
|
||||
coroutine.resume(co);
|
||||
if (counter - int(counter / 1000) * 1000 == 0) {
|
||||
if (counter - int(counter / 2500) * 2500 == 0) {
|
||||
var rate = counter / 2e5;
|
||||
print(" ", bar.bar(rate), " ",
|
||||
padding.leftpad(str(int(rate*100)),3), "% | ",
|
||||
@@ -120,7 +120,7 @@ for (var t = 0; t < 10; t += 1) {
|
||||
}
|
||||
|
||||
tm.stamp();
|
||||
for (var i = 0; i < 1e5; i += 1)
|
||||
for (var i = 0; i < 2e5; i += 1)
|
||||
consumer();
|
||||
println(" ", bar.bar(1), " 100% | ",
|
||||
str(int(1e3 * counter / tm.elapsedMSec())),
|
||||
|
||||
@@ -138,7 +138,7 @@ for (var i = 0; i < 10; i += 1) {
|
||||
append_tree,
|
||||
append_tree,
|
||||
append_tree,
|
||||
|
||||
|
||||
append_hash_vec_hash,
|
||||
append_hash_vec_hash,
|
||||
append_hash_vec_hash,
|
||||
@@ -146,7 +146,7 @@ for (var i = 0; i < 10; i += 1) {
|
||||
append_tree,
|
||||
append_tree,
|
||||
append_tree,
|
||||
|
||||
|
||||
append_hash_vec_hash,
|
||||
append_hash_vec_hash,
|
||||
append_hash_vec_hash,
|
||||
|
||||
@@ -99,7 +99,7 @@ var server = func(ip,port) {
|
||||
result:"null"
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
jsonRPC.disconnect(client);
|
||||
|
||||
@@ -90,7 +90,7 @@ var ppm_gen = func(width,height) {
|
||||
rand(time(0));
|
||||
for (var i=0;i<pixels;i+=1)
|
||||
res[i]=0;
|
||||
|
||||
|
||||
for (var i=int(height/5*2);i<int(height/5*3);i+=1)
|
||||
forindex(var j;res[i])
|
||||
res[i*width+j]=rand()<0.5?1:0;
|
||||
@@ -123,7 +123,7 @@ var ppm_gen = func(width,height) {
|
||||
var bar=process_bar.high_resolution_bar(50);
|
||||
var map=init();
|
||||
var tmp=new_map();
|
||||
|
||||
|
||||
var check = func(_width,_height) {
|
||||
if (_height>=height) _height=0;
|
||||
if (_width>=width) _width=0;
|
||||
|
||||
@@ -274,7 +274,7 @@ var vecfind = func(vec, elem) { return invert(vec)[elem]; }
|
||||
# Note use of "~" operator to do string concatenation (Nasal's only
|
||||
# funny syntax).
|
||||
#
|
||||
var join = func {
|
||||
var join = func {
|
||||
var s = "";
|
||||
foreach(var elem; arg) { s = s ~ elem; }
|
||||
return s;
|
||||
|
||||
@@ -133,7 +133,7 @@ var tmp_f=hash.f;
|
||||
hash=1;
|
||||
println(tmp_f());
|
||||
# undefined symbol 'me'
|
||||
# this means that
|
||||
# this means that
|
||||
# when generating local_scope for function f,
|
||||
# nasal_gc will not count 'me' as one reference of this hash
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ var main = func(argv) {
|
||||
g.move(chr(ch));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
g.next();
|
||||
if (g.gameover())
|
||||
break;
|
||||
|
||||
@@ -84,14 +84,14 @@ var block={
|
||||
exchange();
|
||||
counter=0;
|
||||
}
|
||||
|
||||
|
||||
me.shape=blockshape[me.type[me.rotate]];
|
||||
|
||||
me.color=color_count;
|
||||
color_count+=1;
|
||||
if (color_count>=size(color))
|
||||
color_count=0;
|
||||
|
||||
|
||||
return {parents:[block]};
|
||||
}
|
||||
};
|
||||
@@ -102,7 +102,7 @@ var mapgen = func(mapx,mapy) {
|
||||
|
||||
if (mapx<1 or mapy<1)
|
||||
die("map_x or map_y must be greater than 1");
|
||||
|
||||
|
||||
# use in print
|
||||
var line="";
|
||||
for (var i=0;i<mapx;i+=1)
|
||||
@@ -279,7 +279,7 @@ var main = func(argv) {
|
||||
|
||||
# windows use 65001 to output unicode
|
||||
runtime.windows.set_utf8_output();
|
||||
|
||||
|
||||
print(
|
||||
"\ec\e[1:1H",
|
||||
"╔═════════════════════════╗\n",
|
||||
|
||||
@@ -64,7 +64,7 @@ var run = func(table,start,stop) {
|
||||
die(start~" is not a valid node");
|
||||
if (!contains(machine.states,stop))
|
||||
die(stop~" is not a valid node");
|
||||
|
||||
|
||||
var (state,pointer)=(start,0);
|
||||
|
||||
prt(state,pointer,paper);
|
||||
|
||||
@@ -43,7 +43,7 @@ var map = func() {
|
||||
vec[1][j]=table[-1];
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
tmp=[];
|
||||
foreach(var elem;table)
|
||||
if (elem[2]==vec[1][j-1][4] and elem[1]==vec[0][j][3]) {
|
||||
|
||||
Reference in New Issue
Block a user