Merge pull request #53 from ValKmjolnir/develop

🎨 add new logo & sync some fixes
This commit is contained in:
ValK 2024-08-16 23:18:35 +08:00 committed by GitHub
commit 617598ea40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 171 additions and 87 deletions

View File

@ -56,12 +56,14 @@ target_include_directories(nasal-object PRIVATE ${CMAKE_SOURCE_DIR}/src)
# build nasal
add_executable(nasal ${CMAKE_SOURCE_DIR}/src/main.cpp)
target_link_libraries(nasal nasal-object)
# link ldl and lpthread
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(nasal dl)
target_link_libraries(nasal pthread)
endif()
target_include_directories(nasal PRIVATE ${CMAKE_SOURCE_DIR}/src)
# copy nasal from build dir to the outside dir
if(NOT CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
add_custom_command(

View File

@ -1,4 +1,4 @@
# __Nasal - Modern Interpreter__
# <img src="./doc/svg/nasal_transparent.svg" height="50px"/> __Nasal - Modern Interpreter__
<img src="./doc/pic/header.png" style="width:600px"></img>

View File

@ -1,4 +1,4 @@
# __Nasal - Modern Interpreter__
# <img src="./svg/nasal_transparent.svg" height="50px"/> __Nasal - Modern Interpreter__
<img src="../doc/pic/header.png" style="width:600px"></img>

18
doc/svg/nasal.svg Normal file
View File

@ -0,0 +1,18 @@
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="#9eb0d8"/>
<g transform="translate(6,0)">
<g fill="#1d2c4e">
<!-- left side -->
<path d="M 10 10 L 10 80 L 20 90 L 25 90 L 25 20 L 15 10 Z"/>
<path d="M 10 10 L 85 85 L 85 90 L 70 90 L 10 30 Z"/>
<!-- right-up corner -->
<path d="M 30 10 L 70 50 L 70 55 L 30 15 Z" />
<path d="M 30 10 L 40 10 L 70 40 L 70 55 Z" />
<path d="M 30 10 L 80 10 L 80 15 L 30 15 Z" />
<path d="M 72 10 L 72 55 L 65 55 L 65 10 Z" />
<path d="M 55 10 L 70 25 L 70 35 L 45 10 Z"/>
<path d="M 70 55 L 65 55 L 55 45 L 55 35 Z"/>
<path d="M 70 10 L 80 10 L 80 15 L 70 25 Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 787 B

View File

@ -0,0 +1,18 @@
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- <rect width="100" height="100" fill="#9eb0d8"/> -->
<g transform="translate(6,0)">
<g fill="#6e93e9">
<!-- left side -->
<path d="M 10 10 L 10 80 L 20 90 L 25 90 L 25 20 L 15 10 Z"/>
<path d="M 10 10 L 85 85 L 85 90 L 70 90 L 10 30 Z"/>
<!-- right-up corner -->
<path d="M 30 10 L 70 50 L 70 55 L 30 15 Z" />
<path d="M 30 10 L 40 10 L 70 40 L 70 55 Z" />
<path d="M 30 10 L 80 10 L 80 15 L 30 15 Z" />
<path d="M 72 10 L 72 55 L 65 55 L 65 10 Z" />
<path d="M 55 10 L 70 25 L 70 35 L 45 10 Z"/>
<path d="M 70 55 L 65 55 L 55 45 L 55 35 Z"/>
<path d="M 70 10 L 80 10 L 80 15 L 70 25 Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 796 B

View File

@ -1,4 +1,4 @@
# __Tutorial__
# <img src="./svg/nasal_transparent.svg" height="50px"/> __Tutorial__
![mandelbrotset](../doc/pic/mandelbrotset.png)
@ -517,7 +517,7 @@ nasal_builtin_table builtin[] = {
};
```
At last,warp the `__print` in a nasal file:
At last, wrap the `__print` up in a nasal file:
```javascript
var print = func(elems...) {
@ -534,7 +534,7 @@ var print = func(elems...) {
};
```
If you don't warp built-in function in a normal nasal function,
If you don't wrap built-in function up in a normal nasal function,
this native function may cause __segmentation fault__ when searching arguments.
Use `import("filename.nas")` to get the nasal file including your built-in functions, then you could use it.

View File

@ -1,4 +1,4 @@
# __教程__
# <img src="./svg/nasal_transparent.svg" height="50px"/> __教程__
![mandelbrotset](../doc/pic/mandelbrotset.png)

View File

@ -44,7 +44,7 @@ std::ostream& logo(std::ostream& out) {
<< " - http://fgprc.org\n"
<< " - http://fgprc.org.cn\n"
<< "\n"
<< "input <nasal -h> to get help .\n\n";
<< "input <nasal -h> to get help.\n\n";
return out;
}

View File

@ -49,9 +49,7 @@ void codegen::check_id_exist(identifier* node) {
const auto& name = node->get_name();
if (native_function_mapper.count(name)) {
if (local.empty()) {
die("native function should not be used in global scope",
node->get_location()
);
die("native function should not be used in global scope", node);
}
return;
}
@ -65,9 +63,9 @@ void codegen::check_id_exist(identifier* node) {
if (global_symbol_find(name)>=0) {
return;
}
die("undefined symbol \"" + name +
"\", and this symbol is useless here",
node->get_location()
die("undefined symbol \""
+ name + "\", and this symbol is useless here",
node
);
}
@ -94,17 +92,18 @@ void codegen::regist_string(const std::string& str) {
void codegen::find_symbol(code_block* node) {
auto finder = std::make_unique<symbol_finder>();
for(const auto& i : finder->do_find(node)) {
const auto& file = i.pos_node->get_location().file;
// check if symbol conflicts with native function name
if (native_function_mapper.count(i.name)) {
die("symbol conflicts with native function", i.location);
die("symbol conflicts with native function", i.pos_node);
continue;
}
// create new namespace with checking existence of location file
if (!nasal_namespace.count(i.location.file)) {
nasal_namespace[i.location.file] = {};
if (!nasal_namespace.count(file)) {
nasal_namespace[file] = {};
}
// if in global scope, load global symbol into this namespace
auto& scope = nasal_namespace.at(i.location.file);
auto& scope = nasal_namespace.at(file);
if (local.empty() && !scope.count(i.name)) {
scope.insert(i.name);
}
@ -223,22 +222,16 @@ void codegen::func_gen(function* node) {
if (checked_default &&
tmp->get_parameter_type()!=
parameter::kind::default_parameter) {
die("must use default parameter here",
tmp->get_location()
);
die("must use default parameter here", tmp);
}
if (checked_dynamic &&
tmp!=node->get_parameter_list().back()) {
die("dynamic parameter must be the last one",
tmp->get_location()
);
die("dynamic parameter must be the last one", tmp);
}
// check redefinition
const auto& name = tmp->get_parameter_name();
if (argname.count(name)) {
die("redefinition of parameter: " + name,
tmp->get_location()
);
die("redefinition of parameter: " + name, tmp);
} else {
argname[name] = true;
}
@ -260,9 +253,7 @@ void codegen::func_gen(function* node) {
for(auto tmp : node->get_parameter_list()) {
const auto& name = tmp->get_parameter_name();
if (name=="me") {
die("\"me\" should not be a parameter",
tmp->get_location()
);
die("\"me\" should not be parameter", tmp);
}
regist_string(name);
switch(tmp->get_parameter_type()) {
@ -317,7 +308,7 @@ void codegen::func_gen(function* node) {
if (local.back().size()>=VM_STACK_DEPTH || local.back().size()>=UINT16_MAX) {
die("too many local variants: " +
std::to_string(local.back().size()),
block->get_location()
block
);
}
local.pop_back();
@ -358,9 +349,7 @@ void codegen::call_identifier(identifier* node) {
node->get_location()
);
if (local.empty()) {
die("should warp native function in local scope",
node->get_location()
);
die("should wrap up native function in local scope", node);
}
return;
}
@ -378,7 +367,7 @@ void codegen::call_identifier(identifier* node) {
emit(op_callg, index, node->get_location());
return;
}
die("undefined symbol \"" + name + "\"", node->get_location());
die("undefined symbol \"" + name + "\"", node);
// generation failed, put a push nil operand here to fill the space
emit(op_pnil, index, node->get_location());
}
@ -459,7 +448,7 @@ void codegen::call_func_gen(call_function* node) {
void codegen::mcall(expr* node) {
if (node->get_type()!=expr_type::ast_id &&
node->get_type()!=expr_type::ast_call) {
die("bad left-value: cannot get memory space", node->get_location());
die("bad left-value: cannot get memory space", node);
return;
}
// generate symbol call if node is just ast_id and return
@ -492,18 +481,18 @@ void codegen::mcall(expr* node) {
case expr_type::ast_callv:
mcall_vec(reinterpret_cast<call_vector*>(tmp)); break;
case expr_type::ast_callf:
die("bad left-value: function call", tmp->get_location()); break;
die("bad left-value: function call", tmp); break;
case expr_type::ast_null_access:
die("bad left-value: null access test", tmp->get_location()); break;
die("bad left-value: null access test", tmp); break;
default:
die("bad left-value: unknown call", tmp->get_location()); break;
die("bad left-value: unknown call", tmp); break;
}
}
void codegen::mcall_identifier(identifier* node) {
const auto& name = node->get_name();
if (native_function_mapper.count(name)) {
die("cannot modify native function", node->get_location());
die("cannot modify native function", node);
return;
}
@ -520,17 +509,17 @@ void codegen::mcall_identifier(identifier* node) {
emit(op_mcallg, index, node->get_location());
return;
}
die("undefined symbol \"" + name + "\"", node->get_location());
die("undefined symbol \"" + name + "\"", node);
}
void codegen::mcall_vec(call_vector* node) {
if (node->get_slices().size()>1) {
die("bad left-value: subvec call", node->get_location());
die("bad left-value: subvec call", node);
return;
}
auto call = node->get_slices()[0];
if (call->get_end()) {
die("bad left-value: subvec call", node->get_location());
die("bad left-value: subvec call", node);
return;
}
calc_gen(call->get_begin());
@ -566,14 +555,14 @@ void codegen::multi_def(definition_expr* node) {
die("lack values in multi-definition, expect " +
std::to_string(identifiers.size()) + " but get " +
std::to_string(vals.size()),
node->get_tuple()->get_location()
node->get_tuple()
);
return;
} else if (identifiers.size()<vals.size()) {
die("too many values in multi-definition, expect " +
std::to_string(identifiers.size()) + " but get " +
std::to_string(vals.size()),
node->get_tuple()->get_location()
node->get_tuple()
);
return;
}
@ -600,7 +589,7 @@ void codegen::multi_def(definition_expr* node) {
void codegen::definition_gen(definition_expr* node) {
if (node->get_variable_name() && node->get_tuple()) {
die("cannot accept too many values", node->get_value()->get_location());
die("cannot accept too many values", node->get_value());
}
node->get_variable_name()? single_def(node):multi_def(node);
}
@ -724,7 +713,7 @@ void codegen::gen_assignment_equal_statement(assignment_expr* node) {
case op_mcallg: code.back().op = op_loadg; break;
case op_mcalll: code.back().op = op_loadl; break;
case op_mupval: code.back().op = op_loadu; break;
default: die("unexpected operand to replace", node->get_location());
default: die("unexpected operand to replace", node);
}
}
@ -779,7 +768,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
"lack value(s) in multi-assignment, expect " +
std::to_string(tuple_size) + " but get " +
std::to_string(value_size),
value_node->get_location()
value_node
);
return;
} else if (tuple_size<value_size) {
@ -787,7 +776,7 @@ void codegen::multi_assign_gen(multi_assign* node) {
"too many values in multi-assignment, expect " +
std::to_string(tuple_size) + " but get " +
std::to_string(value_size),
value_node->get_location()
value_node
);
return;
}
@ -1305,13 +1294,9 @@ void codegen::block_gen(code_block* node) {
switch(tmp->get_type()) {
case expr_type::ast_use:
if (!local.empty()) {
die("module import is not allowed here.",
tmp->get_location()
);
die("module import is not allowed here.", tmp);
} else if (!is_use_statement) {
die("module import should be used at the top of the file.",
tmp->get_location()
);
die("module import should be used at top of file.", tmp);
}
break;
case expr_type::ast_null: break;

View File

@ -104,8 +104,8 @@ private:
void check_id_exist(identifier*);
void die(const std::string& info, const span& loc) {
err.err("code", loc, info);
void die(const std::string& info, expr* node) {
err.err("code", node->get_location(), info);
}
void regist_number(const f64);

View File

@ -31,9 +31,11 @@ void vm::vm_init_enrty(const std::vector<std::string>& strs,
/* init vm globals */
auto map_instance = ngc.alloc(vm_type::vm_map);
global_symbol_name.resize(global_symbol.size());
global[global_symbol.at("globals")] = map_instance;
for(const auto& i : global_symbol) {
map_instance.map().mapper[i.first] = global+i.second;
map_instance.map().mapper[i.first] = global + i.second;
global_symbol_name[i.second] = i.first;
}
/* init vm arg */
@ -144,21 +146,21 @@ void vm::namespace_value_info(var& val, const usize max_show_elems) {
void vm::value_name_form(const var& val) {
std::clog << "| ";
switch(val.type) {
case vm_type::vm_none: std::clog << "null "; break;
case vm_type::vm_ret: std::clog << "ret "; break;
case vm_type::vm_addr: std::clog << "addr "; break;
case vm_type::vm_cnt: std::clog << "cnt "; break;
case vm_type::vm_nil: std::clog << "nil "; break;
case vm_type::vm_num: std::clog << "num "; break;
case vm_type::vm_str: std::clog << "str "; break;
case vm_type::vm_func: std::clog << "func "; break;
case vm_type::vm_upval: std::clog << "upval "; break;
case vm_type::vm_vec: std::clog << "vec "; break;
case vm_type::vm_hash: std::clog << "hash "; break;
case vm_type::vm_ghost: std::clog << "ghost "; break;
case vm_type::vm_co: std::clog << "co "; break;
case vm_type::vm_map: std::clog << "map "; break;
default: std::clog << "err "; break;
case vm_type::vm_none: std::clog << "null "; break;
case vm_type::vm_ret: std::clog << "ret "; break;
case vm_type::vm_addr: std::clog << "addr "; break;
case vm_type::vm_cnt: std::clog << "cnt "; break;
case vm_type::vm_nil: std::clog << "nil "; break;
case vm_type::vm_num: std::clog << "num "; break;
case vm_type::vm_str: std::clog << "str "; break;
case vm_type::vm_func: std::clog << "func "; break;
case vm_type::vm_upval: std::clog << "upval"; break;
case vm_type::vm_vec: std::clog << "vec "; break;
case vm_type::vm_hash: std::clog << "hash "; break;
case vm_type::vm_ghost: std::clog << "ghost"; break;
case vm_type::vm_co: std::clog << "co "; break;
case vm_type::vm_map: std::clog << "map "; break;
default: std::clog << "err "; break;
}
std::clog << " | ";
}
@ -344,16 +346,16 @@ void vm::stack_info(const u64 limit = 16) {
void vm::register_info() {
std::clog << "\nregister (" << (ngc.cort? "coroutine":"main") << ")\n";
std::clog << std::hex
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
<< " [ global ] | addr | 0x"
<< " [ pc ] | pc | 0x" << ctx.pc << "\n"
<< " [ global ] | addr | 0x"
<< reinterpret_cast<u64>(global) << "\n"
<< " [ local ] | addr | 0x"
<< " [ local ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.localr) << "\n"
<< " [ memr ] | addr | 0x"
<< " [ memr ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.memr) << "\n"
<< " [ canary ] | addr | 0x"
<< " [ canary ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.canary) << "\n"
<< " [ top ] | addr | 0x"
<< " [ top ] | addr | 0x"
<< reinterpret_cast<u64>(ctx.top) << "\n"
<< std::dec;
std::clog << " [ funcr ] "; value_info(ctx.funcr);
@ -370,6 +372,14 @@ void vm::global_state() {
std::clog << " 0x" << std::hex << std::setw(8)
<< std::setfill('0') << i << std::dec
<< " ";
auto name = global_symbol_name[i];
if (name.length()>=10) {
name = name.substr(0, 7) + "...";
} else {
}
std::clog << "| " << std::left << std::setw(10)
<< std::setfill(' ') << name << " ";
value_info(global[i]);
}
}

View File

@ -42,6 +42,7 @@ protected:
/* values used for debugger */
const std::string* files = nullptr; // file name list
const opcode* bytecode = nullptr; // bytecode buffer address
std::vector<std::string> global_symbol_name; // global symbol name
/* variables for repl mode */
bool is_repl_mode = false;

View File

@ -8,16 +8,13 @@ bool symbol_finder::visit_definition_expr(definition_expr* node) {
// example: var a = 1;
symbols.push_back({
node->get_variable_name()->get_name(),
node->get_variable_name()->get_location()
node->get_variable_name()
});
} else {
// multiple variable definition
// example: var (a, b, c) = (0, 1, 2);
for(auto i : node->get_variables()->get_variables()) {
symbols.push_back({
i->get_name(),
i->get_location()
});
symbols.push_back({i->get_name(), i});
}
}
if (node->get_tuple()) {
@ -37,7 +34,7 @@ bool symbol_finder::visit_iter_expr(iter_expr* node) {
if (node->is_definition() && node->get_name()) {
symbols.push_back({
node->get_name()->get_name(),
node->get_name()->get_location()
node->get_name()
});
}
return true;

View File

@ -13,7 +13,7 @@ class symbol_finder: public ast_visitor {
public:
struct symbol_info {
std::string name;
span location;
identifier* pos_node;
};
private:

View File

@ -37,11 +37,11 @@ var cpu_occupation = func() {
while(1) {
var cpu0 = cpu_stat();
if (first_in) {
unix.sleep(0.1);
unix.sleep(0.05);
first_in = 0;
} else {
for(var i = 0; i < 10; i += 1) {
unix.sleep(0.1);
unix.sleep(0.05);
coroutine.yield(nil);
}
}

53
test/tui.nas Normal file
View File

@ -0,0 +1,53 @@
use std.utils;
use std.unix;
var screen_state = {
width: 0,
height: 0
};
screen_state.update = func() {
var res = utils.terminal_size();
me.width = res.cols;
me.height = res.rows;
}
screen_state.clear_screen = func() {
me.update();
var screen = "\e[0;0H";
for (var i = 0; i < me.height; i+=1) {
for (var j = 0; j < me.width; j+=1) {
screen ~= " ";
}
if (i != me.height - 1)
screen ~= "\n";
}
print(screen, "\e[0;0H");
}
screen_state.put_pixel = func(x, y, c) {
x = int(x);
y = int(y);
if (x < 0 or x >= me.width or y < 0 or y >= me.height)
return;
var coord = "\e[" ~ y ~ ";" ~ x ~ "H";
print(coord, c, "\e[0;0H");
}
var test_flush = func() {
screen_state.clear_screen();
for(var i=0; i<1e6; i+=1) {
unix.sleep(0.001);
screen_state.update();
screen_state.put_pixel(
rand()*screen_state.width,
rand()*screen_state.height,
"\e[38;5;" ~ int(256*rand()) ~ "m" ~ char(65 + 26*rand()) ~ "\e[0m"
);
print("\e[0;0H", i);
}
screen_state.clear_screen();
println();
}