✨ add new import & use c++17
This commit is contained in:
parent
89f96d407b
commit
c516c0c3bf
|
@ -5,7 +5,7 @@ project(nasal VERSION 10.1)
|
|||
message("CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
|
||||
|
||||
# -std=c++14 -Wshadow -Wall
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-Wshadow -Wall")
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ __Contact us if having great ideas to share!__
|
|||
is an ECMAscript-like language used in [FlightGear](https://www.flightgear.org/).
|
||||
The designer is [Andy Ross](https://github.com/andyross).
|
||||
|
||||
This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++14`)
|
||||
This interpreter is totally rewritten by [ValKmjolnir](https://github.com/ValKmjolnir) using `C++`(`-std=c++17`)
|
||||
without reusing the code in [Andy Ross's nasal interpreter](https://github.com/andyross/nasal).
|
||||
But we really appreciate that Andy created this amazing programming language.
|
||||
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
bool ast_dumper::visit_file_info(file_info* node) {
|
||||
dump_indent();
|
||||
std::cout << "file \"" << node->get_file_name() << "\"";
|
||||
std::cout << format_location(node->get_location());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_dumper::visit_null_expr(null_expr* node) {
|
||||
dump_indent();
|
||||
std::cout << "null" << format_location(node->get_location());
|
||||
|
|
|
@ -33,12 +33,13 @@ private:
|
|||
std::stringstream ss;
|
||||
ss << " -> ";
|
||||
ss << location.file << ":";
|
||||
ss << location.begin_line << ":" << location.begin_column;
|
||||
ss << location.begin_line << ":" << location.begin_column + 1;
|
||||
ss << "\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
public:
|
||||
bool visit_file_info(file_info*) override;
|
||||
bool visit_null_expr(null_expr*) override;
|
||||
bool visit_nil_expr(nil_expr*) override;
|
||||
bool visit_number_literal(number_literal*) override;
|
||||
|
|
|
@ -5,6 +5,10 @@ bool ast_visitor::visit_expr(expr* node) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_file_info(file_info* node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ast_visitor::visit_null_expr(null_expr* node) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
class ast_visitor {
|
||||
public:
|
||||
virtual bool visit_expr(expr*);
|
||||
virtual bool visit_file_info(file_info*);
|
||||
virtual bool visit_null_expr(null_expr*);
|
||||
virtual bool visit_nil_expr(nil_expr*);
|
||||
virtual bool visit_number_literal(number_literal*);
|
||||
|
|
|
@ -5,6 +5,10 @@ void expr::accept(ast_visitor* visitor) {
|
|||
visitor->visit_expr(this);
|
||||
}
|
||||
|
||||
void file_info::accept(ast_visitor* visitor) {
|
||||
visitor->visit_file_info(this);
|
||||
}
|
||||
|
||||
void null_expr::accept(ast_visitor* visitor) {
|
||||
visitor->visit_null_expr(this);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
enum class expr_type:u32 {
|
||||
ast_null=0, // null node
|
||||
ast_file_info, // stores file info
|
||||
ast_block, // code block
|
||||
ast_nil, // nil keyword
|
||||
ast_num, // number, basic value type
|
||||
|
@ -73,6 +74,21 @@ public:
|
|||
virtual void accept(ast_visitor*);
|
||||
};
|
||||
|
||||
class file_info:public expr {
|
||||
private:
|
||||
uint16_t index;
|
||||
std::string filename;
|
||||
|
||||
public:
|
||||
file_info(const span& location, uint16_t file_index, const std::string& name):
|
||||
expr(location, expr_type::ast_file_info),
|
||||
index(file_index), filename(name) {}
|
||||
~file_info() = default;
|
||||
uint16_t get_index() const {return index;}
|
||||
const std::string& get_file_name() const {return filename;}
|
||||
void accept(ast_visitor*) override;
|
||||
};
|
||||
|
||||
class null_expr:public expr {
|
||||
public:
|
||||
null_expr(const span& location):
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
#include "nasal_new_import.h"
|
||||
|
||||
linker::linker(error& e): show_path(false), lib_loaded(false), err(e) {
|
||||
char sep=is_windows()? ';':':';
|
||||
std::string PATH=getenv("PATH");
|
||||
usize last=0;
|
||||
usize pos=PATH.find(sep, 0);
|
||||
while(pos!=std::string::npos) {
|
||||
std::string dirpath=PATH.substr(last, pos-last);
|
||||
if (dirpath.length()) {
|
||||
envpath.push_back(dirpath);
|
||||
}
|
||||
last=pos+1;
|
||||
pos=PATH.find(sep, last);
|
||||
}
|
||||
if (last!=PATH.length()) {
|
||||
envpath.push_back(PATH.substr(last));
|
||||
}
|
||||
}
|
||||
|
||||
std::string linker::get_path(call_expr* node) {
|
||||
if (node->get_calls()[0]->get_type()==expr_type::ast_callf) {
|
||||
auto tmp = (call_function*)node->get_calls()[0];
|
||||
return ((string_literal*)tmp->get_argument()[0])->get_content();
|
||||
}
|
||||
auto fpath = std::string(".");
|
||||
for(auto i : node->get_calls()) {
|
||||
fpath += (is_windows()? "\\":"/") + ((call_hash*)i)->get_field();
|
||||
}
|
||||
return fpath + ".nas";
|
||||
}
|
||||
|
||||
std::string linker::find_file(const std::string& filename) {
|
||||
// first add file name itself into the file path
|
||||
std::vector<std::string> fpath = {filename};
|
||||
|
||||
// generate search path from environ path
|
||||
for(const auto& p : envpath) {
|
||||
fpath.push_back(p + (is_windows()? "\\":"/") + filename);
|
||||
}
|
||||
|
||||
// search file
|
||||
for(const auto& i : fpath) {
|
||||
if (access(i.c_str(), F_OK)!=-1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// we will find lib.nas in nasal std directory
|
||||
if (filename=="lib.nas") {
|
||||
return is_windows()? find_file("stl\\lib.nas"):find_file("stl/lib.nas");
|
||||
}
|
||||
if (!show_path) {
|
||||
err.err("link", "cannot find file <" + filename + ">");
|
||||
return "";
|
||||
}
|
||||
std::string paths = "";
|
||||
for(const auto& i : fpath) {
|
||||
paths += " " + i + "\n";
|
||||
}
|
||||
err.err("link", "cannot find file <" + filename + "> in these paths:\n" + paths);
|
||||
return "";
|
||||
}
|
||||
|
||||
bool linker::import_check(expr* node) {
|
||||
/*
|
||||
call
|
||||
|_id:import
|
||||
|_callh:stl
|
||||
|_callh:file
|
||||
*/
|
||||
if (node->get_type()!=expr_type::ast_call) {
|
||||
return false;
|
||||
}
|
||||
auto tmp = (call_expr*)node;
|
||||
if (tmp->get_first()->get_type()!=expr_type::ast_id) {
|
||||
return false;
|
||||
}
|
||||
if (((identifier*)tmp->get_first())->get_name()!="import") {
|
||||
return false;
|
||||
}
|
||||
if (!tmp->get_calls().size()) {
|
||||
return false;
|
||||
}
|
||||
// import.xxx.xxx;
|
||||
if (tmp->get_calls()[0]->get_type()==expr_type::ast_callh) {
|
||||
for(auto i : tmp->get_calls()) {
|
||||
if (i->get_type()!=expr_type::ast_callh) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// import("xxx");
|
||||
if (tmp->get_calls().size()!=1) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
call
|
||||
|_id:import
|
||||
|_call_func
|
||||
|_string:'filename'
|
||||
*/
|
||||
if (tmp->get_calls()[0]->get_type()!=expr_type::ast_callf) {
|
||||
return false;
|
||||
}
|
||||
auto func_call = (call_function*)tmp->get_calls()[0];
|
||||
if (func_call->get_argument().size()!=1) {
|
||||
return false;
|
||||
}
|
||||
if (func_call->get_argument()[0]->get_type()!=expr_type::ast_str) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool linker::exist(const std::string& file) {
|
||||
// avoid importing the same file
|
||||
for(const auto& fname : files) {
|
||||
if (file==fname) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
files.push_back(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
|
||||
// add children of add_root to the back of root
|
||||
for(auto& i:old_tree_root->get_expressions()) {
|
||||
new_tree_root->add_expression(i);
|
||||
}
|
||||
// clean old root
|
||||
old_tree_root->get_expressions().clear();
|
||||
}
|
||||
|
||||
code_block* linker::import_regular_file(call_expr* node) {
|
||||
lexer lex(err);
|
||||
parse par(err);
|
||||
// get filename and set node to ast_null
|
||||
auto filename = get_path(node);
|
||||
// node.clear();
|
||||
|
||||
// avoid infinite loading loop
|
||||
filename = find_file(filename);
|
||||
if (!filename.length() || exist(filename)) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
|
||||
// start importing...
|
||||
lex.scan(filename);
|
||||
par.compile(lex);
|
||||
auto tmp = par.swap(nullptr);
|
||||
|
||||
// check if tmp has 'import'
|
||||
return load(tmp, files.size()-1);
|
||||
}
|
||||
|
||||
code_block* linker::import_nasal_lib() {
|
||||
lexer lex(err);
|
||||
parse par(err);
|
||||
auto filename = find_file("lib.nas");
|
||||
if (!filename.length()) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
|
||||
// avoid infinite loading loop
|
||||
if (exist(filename)) {
|
||||
return new code_block({0, 0, 0, 0, filename});
|
||||
}
|
||||
|
||||
// start importing...
|
||||
lex.scan(filename);
|
||||
par.compile(lex);
|
||||
auto tmp = par.swap(nullptr);
|
||||
|
||||
// check if tmp has 'import'
|
||||
return load(tmp, files.size()-1);
|
||||
}
|
||||
|
||||
code_block* linker::load(code_block* root, u16 fileindex) {
|
||||
auto tree = new code_block({0, 0, 0, 0, files[fileindex]});
|
||||
if (!lib_loaded) {
|
||||
auto tmp = import_nasal_lib();
|
||||
link(tree, tmp);
|
||||
delete tmp;
|
||||
lib_loaded = true;
|
||||
}
|
||||
for(auto i : root->get_expressions()) {
|
||||
if (!import_check(i)) {
|
||||
break;
|
||||
}
|
||||
auto tmp = import_regular_file((call_expr*)i);
|
||||
link(tree, tmp);
|
||||
delete tmp;
|
||||
}
|
||||
// add root to the back of tree
|
||||
auto file_head = new file_info(
|
||||
{0, 0, 0, 0, files[fileindex]}, fileindex, files[fileindex]);
|
||||
tree->add_expression(file_head);
|
||||
link(tree, root);
|
||||
return tree;
|
||||
}
|
||||
|
||||
const error& linker::link(
|
||||
parse& parse, const std::string& self, bool spath = false) {
|
||||
show_path = spath;
|
||||
// initializing
|
||||
files = {self};
|
||||
// scan root and import files
|
||||
// then generate a new ast and return to import_ast
|
||||
// the main file's index is 0
|
||||
auto new_tree_root = load(parse.tree(), 0);
|
||||
auto old_tree_root = parse.swap(new_tree_root);
|
||||
delete old_tree_root;
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define F_OK 0
|
||||
#endif
|
||||
|
||||
#include "nasal_new_header.h"
|
||||
#include "nasal_new_ast.h"
|
||||
#include "nasal_new_lexer.h"
|
||||
#include "nasal_new_parse.h"
|
||||
|
||||
class linker{
|
||||
private:
|
||||
bool show_path;
|
||||
bool lib_loaded;
|
||||
error& err;
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::string> envpath;
|
||||
|
||||
bool import_check(expr*);
|
||||
bool exist(const std::string&);
|
||||
void link(code_block*, code_block*);
|
||||
std::string get_path(call_expr*);
|
||||
std::string find_file(const std::string&);
|
||||
code_block* import_regular_file(call_expr*);
|
||||
code_block* import_nasal_lib();
|
||||
code_block* load(code_block*, u16);
|
||||
public:
|
||||
linker(error&);
|
||||
const error& link(parse&, const std::string&, bool);
|
||||
const std::vector<std::string>& filelist() const {return files;}
|
||||
};
|
|
@ -3,6 +3,7 @@
|
|||
#include "nasal_new_lexer.h"
|
||||
#include "nasal_new_ast.h"
|
||||
#include "nasal_new_parse.h"
|
||||
#include "nasal_new_import.h"
|
||||
#include "ast_visitor.h"
|
||||
#include "ast_dumper.h"
|
||||
|
||||
|
@ -78,7 +79,7 @@ void execute(
|
|||
error err;
|
||||
lexer lex(err);
|
||||
parse parse(err);
|
||||
// linker ld(err);
|
||||
linker ld(err);
|
||||
// codegen gen(err);
|
||||
// vm ctx;
|
||||
|
||||
|
@ -87,14 +88,14 @@ void execute(
|
|||
|
||||
// parser gets lexer's token list to compile
|
||||
parse.compile(lex).chkerr();
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
ld.link(parse, file, cmd&VM_DETAIL).chkerr();
|
||||
if (cmd&VM_AST) {
|
||||
auto dumper = new ast_dumper();
|
||||
dumper->visit_code_block(parse.tree());
|
||||
}
|
||||
|
||||
// linker gets parser's ast and load import files to this ast
|
||||
// ld.link(parse, file, cmd&VM_DETAIL).chkerr();
|
||||
|
||||
// optimizer does simple optimization on ast
|
||||
// optimize(parse.tree());
|
||||
|
||||
|
|
|
@ -136,7 +136,14 @@ private:
|
|||
return_expr* return_expression();
|
||||
|
||||
public:
|
||||
inline code_block* tree() {return root;}
|
||||
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(error& e):
|
||||
|
@ -144,6 +151,11 @@ public:
|
|||
toks(nullptr),
|
||||
root(nullptr),
|
||||
err(e) {}
|
||||
~parse() {
|
||||
if (root) {
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
const error& compile(const lexer&);
|
||||
void easter_egg() const;
|
||||
};
|
8
makefile
8
makefile
|
@ -16,7 +16,7 @@ SRC=\
|
|||
nasal_dbg.h\
|
||||
nasal.h
|
||||
|
||||
STD=c++14
|
||||
STD=c++17
|
||||
|
||||
nasal:$(SRC)
|
||||
$(CXX) -std=$(STD) -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
|
||||
|
@ -76,6 +76,7 @@ test:nasal
|
|||
NASAL_NEW_AST=\
|
||||
nasal_new_misc.o\
|
||||
nasal_new_err.o\
|
||||
nasal_new_import.o\
|
||||
nasal_new_lexer.o\
|
||||
nasal_new_ast.o\
|
||||
nasal_new_parse.o\
|
||||
|
@ -97,8 +98,11 @@ nasal_new_misc.o: ast/nasal_new_header.h ast/nasal_new_misc.cpp
|
|||
nasal_new_err.o: ast/nasal_new_err.h ast/nasal_new_err.cpp
|
||||
$(CXX) -std=$(STD) -c -O3 ast/nasal_new_err.cpp -fno-exceptions -fPIC -o nasal_new_err.o -I .
|
||||
|
||||
nasal_new_import.o: ast/nasal_new_import.h ast/nasal_new_import.cpp
|
||||
$(CXX) --std=$(STD) -c -O3 ast/nasal_new_import.cpp -fno-exceptions -fPIC -o nasal_new_import.o -I .
|
||||
|
||||
nasal_new_lexer.o: ast/nasal_new_lexer.h ast/nasal_new_lexer.cpp
|
||||
$(CXX) -std=$(STD) -c -O3 ast/nasal_new_lexer.cpp -fno-exceptions -fPIC -o nasal_new_lexer.o -I .
|
||||
$(CXX) --std=$(STD) -c -O3 ast/nasal_new_lexer.cpp -fno-exceptions -fPIC -o nasal_new_lexer.o -I .
|
||||
|
||||
nasal_new_ast.o: ast/nasal_new_ast.h ast/nasal_new_ast.cpp
|
||||
$(CXX) -std=$(STD) -c -O3 ast/nasal_new_ast.cpp -fno-exceptions -fPIC -o nasal_new_ast.o -I .
|
||||
|
|
|
@ -5,7 +5,7 @@ dynamic_libs_dll=libfib.dll libkey.dll libnasock.dll libmat.dll
|
|||
|
||||
used_header= ../nasal.h ../nasal_gc.h
|
||||
|
||||
STD=c++14
|
||||
STD=c++17
|
||||
|
||||
all: $(dynamic_libs_so)
|
||||
@ echo "[Compiling] done"
|
||||
|
|
Loading…
Reference in New Issue