9 Commits

Author SHA1 Message Date
ValK
9014dc9aa4 Merge pull request #79 from ValKmjolnir/develop
Some checks failed
Nasal Interpreter Test / mac-aarch64 (push) Has been cancelled
Nasal Interpreter Test / linux-x86_64 (push) Has been cancelled
🎨 cumulative update
2026-02-02 00:54:58 +08:00
ValKmjolnir
b68aa5b205 🎨 format code
Some checks failed
Nasal Interpreter Test / mac-aarch64 (push) Has been cancelled
Nasal Interpreter Test / linux-x86_64 (push) Has been cancelled
Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
2026-02-01 22:17:03 +08:00
ValKmjolnir
7ac30da69e 📝 move zh README to root
Some checks failed
Nasal Interpreter Test / mac-aarch64 (push) Has been cancelled
Nasal Interpreter Test / linux-x86_64 (push) Has been cancelled
Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
2026-01-22 22:33:54 +08:00
ValKmjolnir
b923875fc5 mark in_curve in expr node
Some checks are pending
Nasal Interpreter Test / mac-aarch64 (push) Waiting to run
Nasal Interpreter Test / linux-x86_64 (push) Waiting to run
Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
2026-01-21 23:29:33 +08:00
ValKmjolnir
7d9aeb6246 📝 update README
Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
2026-01-21 21:36:01 +08:00
ValKmjolnir
804d9a24b8 Merge branch 'master' into develop 2026-01-19 23:57:32 +08:00
ValKmjolnir
f0240fd6dc 📝 adjust files 2025-10-24 20:08:51 +08:00
ValKmjolnir
305a825a3c finish caller
Signed-off-by: ValKmjolnir <lhk101lhk101@qq.com>
2025-10-24 00:03:43 +08:00
ValKmjolnir
eff7d4b725 🎨 prepare to impl caller 2025-10-23 00:06:16 +08:00
61 changed files with 4044 additions and 4239 deletions

View File

@@ -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

View File

@@ -9,7 +9,7 @@
[![Test CI](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml/badge.svg)](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml)
![star](https://gitcode.com/ValKmjolnir/Nasal-Interpreter/star/badge.svg)
> 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

View File

@@ -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>
![GitHub release(latest by date)](https://img.shields.io/github/v/release/ValKmjolnir/Nasal-Interpreter?style=flat-square&logo=github)
[![license](https://img.shields.io/badge/license-GPLv2-green?style=flat-square&logo=github)](../LICENSE)
![downloads](https://img.shields.io/github/downloads/ValKmjolnir/Nasal-Interpreter/total.svg?style=flat-square&logo=github)
[![C/C++ CI](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/c-cpp.yml)
[![Test CI](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml/badge.svg)](https://github.com/ValKmjolnir/Nasal-Interpreter/actions/workflows/test.yml)
![star](https://gitcode.com/ValKmjolnir/Nasal-Interpreter/star/badge.svg)
> 这篇文档包含多语言版本: [__中文__](../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 平台的预览版解释器现在还没配置相关流水线,
## __使用方法__
![usage](../doc/gif/help.gif)
![usage](doc/gif/help.gif)
如果你是 `Windows` 用户且想正常输出 unicode可以这样开启 unicode 代码页:
@@ -116,7 +117,7 @@ runtime.windows.set_utf8_output();
## __与andy解释器的不同之处__
![error](../doc/gif/error.gif)
![error](doc/gif/error.gif)
<details><summary>必须用 var 定义变量</summary>
@@ -151,7 +152,7 @@ code: undefined symbol "i"
## __堆栈追踪信息__
![stackoverflow](../doc/gif/stackoverflow.gif)
![stackoverflow](doc/gif/stackoverflow.gif)
当解释器崩溃时,它会反馈错误产生过程的堆栈追踪信息:
@@ -316,7 +317,7 @@ local (0x55dcb5b43190 <+7>)
## __调试器__
![dbg](../doc/gif/dbg.gif)
![dbg](doc/gif/dbg.gif)
`v8.0`版本中我们添加了调试器。
使用这个命令`./nasal -dbg xxx.nas`来启用调试器,接下来调试器会打开文件并输出以下内容:

281
makefile
View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -1,4 +1,4 @@
#include "nasal_ast.h"
#include "ast.h"
#include "ast_visitor.h"
namespace nasal {

View File

@@ -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; }

View File

@@ -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;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "nasal_ast.h"
#include "ast.h"
namespace nasal {

View File

@@ -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)) {

View File

@@ -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) {

View File

@@ -1,7 +1,7 @@
#pragma once
#ifndef __nasver__
#define __nasver__ "11.3.3"
#define __nasver__ "11.3.4"
#endif
#include <cstddef>

View File

@@ -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";

View File

@@ -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);
}

View File

@@ -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()) {

View File

@@ -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);

View File

@@ -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() {...}

View File

@@ -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"

View File

@@ -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) {

View File

@@ -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*,

File diff suppressed because it is too large Load Diff

View File

@@ -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();
};
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -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()) {

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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&);

View File

@@ -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",

View File

@@ -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 ||

View File

@@ -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

View File

@@ -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 {

View File

@@ -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();

View File

@@ -48,7 +48,7 @@ public:
// set empty history
command_history = {""};
}
// Make these methods public for web REPL
bool run();
void execute();

View File

@@ -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>

View File

@@ -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.");
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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");

View File

@@ -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
View 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();

View File

@@ -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())),

View File

@@ -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,

View File

@@ -99,7 +99,7 @@ var server = func(ip,port) {
result:"null"
}));
}
}
}
jsonRPC.disconnect(client);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -153,7 +153,7 @@ var main = func(argv) {
g.move(chr(ch));
}
}
g.next();
if (g.gameover())
break;

View File

@@ -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",

View File

@@ -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);

View File

@@ -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]) {