📝 change CRLF to LF
This commit is contained in:
parent
476fbdb859
commit
d42e4a5897
496
src/io_lib.cpp
496
src/io_lib.cpp
|
@ -1,245 +1,251 @@
|
||||||
#include "io_lib.h"
|
#include "io_lib.h"
|
||||||
|
|
||||||
namespace nasal {
|
#ifdef _MSC_VER
|
||||||
|
#define F_OK 0 // fuck msc
|
||||||
const auto file_type_name = "file";
|
#endif
|
||||||
|
|
||||||
void filehandle_destructor(void* ptr) {
|
#include <sys/stat.h>
|
||||||
fclose(static_cast<FILE*>(ptr));
|
|
||||||
}
|
namespace nasal {
|
||||||
|
|
||||||
var builtin_readfile(context* ctx, gc* ngc) {
|
const auto file_type_name = "file";
|
||||||
auto filename = ctx->localr[1];
|
|
||||||
if (!filename.is_str()) {
|
void filehandle_destructor(void* ptr) {
|
||||||
return nas_err("io::readfile", "\"filename\" must be string");
|
fclose(static_cast<FILE*>(ptr));
|
||||||
}
|
}
|
||||||
std::ifstream in(filename.str(), std::ios::binary);
|
|
||||||
std::stringstream rd;
|
var builtin_readfile(context* ctx, gc* ngc) {
|
||||||
if (!in.fail()) {
|
auto filename = ctx->localr[1];
|
||||||
rd << in.rdbuf();
|
if (!filename.is_str()) {
|
||||||
}
|
return nas_err("io::readfile", "\"filename\" must be string");
|
||||||
return ngc->newstr(rd.str());
|
}
|
||||||
}
|
std::ifstream in(filename.str(), std::ios::binary);
|
||||||
|
std::stringstream rd;
|
||||||
var builtin_fout(context* ctx, gc* ngc) {
|
if (!in.fail()) {
|
||||||
auto local = ctx->localr;
|
rd << in.rdbuf();
|
||||||
auto filename = local[1];
|
}
|
||||||
auto source = local[2];
|
return ngc->newstr(rd.str());
|
||||||
if (!filename.is_str()) {
|
}
|
||||||
return nas_err("io::fout", "\"filename\" must be string");
|
|
||||||
}
|
var builtin_fout(context* ctx, gc* ngc) {
|
||||||
std::ofstream out(filename.str());
|
auto local = ctx->localr;
|
||||||
if (out.fail()) {
|
auto filename = local[1];
|
||||||
return nas_err("io::fout", "cannot open <" + filename.str() + ">");
|
auto source = local[2];
|
||||||
}
|
if (!filename.is_str()) {
|
||||||
out << source;
|
return nas_err("io::fout", "\"filename\" must be string");
|
||||||
return nil;
|
}
|
||||||
}
|
std::ofstream out(filename.str());
|
||||||
|
if (out.fail()) {
|
||||||
var builtin_exists(context* ctx, gc* ngc) {
|
return nas_err("io::fout", "cannot open <" + filename.str() + ">");
|
||||||
auto filename = ctx->localr[1];
|
}
|
||||||
if (!filename.is_str()) {
|
out << source;
|
||||||
return zero;
|
return nil;
|
||||||
}
|
}
|
||||||
return access(filename.str().c_str(), F_OK)!=-1? one:zero;
|
|
||||||
}
|
var builtin_exists(context* ctx, gc* ngc) {
|
||||||
|
auto filename = ctx->localr[1];
|
||||||
var builtin_open(context* ctx, gc* ngc) {
|
if (!filename.is_str()) {
|
||||||
auto local = ctx->localr;
|
return zero;
|
||||||
auto name = local[1];
|
}
|
||||||
auto mode = local[2];
|
return access(filename.str().c_str(), F_OK)!=-1? one:zero;
|
||||||
if (!name.is_str()) {
|
}
|
||||||
return nas_err("io::open", "\"filename\" must be string");
|
|
||||||
}
|
var builtin_open(context* ctx, gc* ngc) {
|
||||||
if (!mode.is_str()) {
|
auto local = ctx->localr;
|
||||||
return nas_err("io::open", "\"mode\" must be string");
|
auto name = local[1];
|
||||||
}
|
auto mode = local[2];
|
||||||
auto file_descriptor = fopen(name.str().c_str(), mode.str().c_str());
|
if (!name.is_str()) {
|
||||||
if (!file_descriptor) {
|
return nas_err("io::open", "\"filename\" must be string");
|
||||||
return nas_err("io::open", "failed to open file <" + name.str() + ">");
|
}
|
||||||
}
|
if (!mode.is_str()) {
|
||||||
var return_object = ngc->alloc(vm_type::vm_ghost);
|
return nas_err("io::open", "\"mode\" must be string");
|
||||||
return_object.ghost().set(
|
}
|
||||||
file_type_name, filehandle_destructor, nullptr, file_descriptor
|
auto file_descriptor = fopen(name.str().c_str(), mode.str().c_str());
|
||||||
);
|
if (!file_descriptor) {
|
||||||
return return_object;
|
return nas_err("io::open", "failed to open file <" + name.str() + ">");
|
||||||
}
|
}
|
||||||
|
var return_object = ngc->alloc(vm_type::vm_ghost);
|
||||||
var builtin_close(context* ctx, gc* ngc) {
|
return_object.ghost().set(
|
||||||
var file_descriptor = ctx->localr[1];
|
file_type_name, filehandle_destructor, nullptr, file_descriptor
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
);
|
||||||
return nas_err("io::close", "not a valid filehandle");
|
return return_object;
|
||||||
}
|
}
|
||||||
file_descriptor.ghost().clear();
|
|
||||||
return nil;
|
var builtin_close(context* ctx, gc* ngc) {
|
||||||
}
|
var file_descriptor = ctx->localr[1];
|
||||||
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
var builtin_read(context* ctx, gc* ngc) {
|
return nas_err("io::close", "not a valid filehandle");
|
||||||
auto local = ctx->localr;
|
}
|
||||||
auto file_descriptor = local[1];
|
file_descriptor.ghost().clear();
|
||||||
auto buffer = local[2];
|
return nil;
|
||||||
auto length = local[3];
|
}
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
|
||||||
return nas_err("io::read", "not a valid filehandle");
|
var builtin_read(context* ctx, gc* ngc) {
|
||||||
}
|
auto local = ctx->localr;
|
||||||
if (!buffer.is_str() || buffer.val.gcobj->unmutable) {
|
auto file_descriptor = local[1];
|
||||||
return nas_err("io::read", "\"buf\" must be mutable string");
|
auto buffer = local[2];
|
||||||
}
|
auto length = local[3];
|
||||||
if (!length.is_num()) {
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
return nas_err("io::read", "\"len\" must be number");
|
return nas_err("io::read", "not a valid filehandle");
|
||||||
}
|
}
|
||||||
if (length.num()<=0 || length.num()>=(1<<30)) {
|
if (!buffer.is_str() || buffer.val.gcobj->unmutable) {
|
||||||
return nas_err("io::read", "\"len\" less than 1 or too large");
|
return nas_err("io::read", "\"buf\" must be mutable string");
|
||||||
}
|
}
|
||||||
auto temp_buffer = new char[static_cast<usize>(length.num())+1];
|
if (!length.is_num()) {
|
||||||
if (!temp_buffer) {
|
return nas_err("io::read", "\"len\" must be number");
|
||||||
return nas_err("io::read", "malloc failed");
|
}
|
||||||
}
|
if (length.num()<=0 || length.num()>=(1<<30)) {
|
||||||
auto read_size = fread(
|
return nas_err("io::read", "\"len\" less than 1 or too large");
|
||||||
temp_buffer, 1, length.num(),
|
}
|
||||||
static_cast<FILE*>(file_descriptor.ghost().pointer)
|
auto temp_buffer = new char[static_cast<usize>(length.num())+1];
|
||||||
);
|
if (!temp_buffer) {
|
||||||
buffer.str() = temp_buffer;
|
return nas_err("io::read", "malloc failed");
|
||||||
buffer.val.gcobj->unmutable = true;
|
}
|
||||||
delete []temp_buffer;
|
auto read_size = fread(
|
||||||
return var::num(read_size);
|
temp_buffer, 1, length.num(),
|
||||||
}
|
static_cast<FILE*>(file_descriptor.ghost().pointer)
|
||||||
|
);
|
||||||
var builtin_write(context* ctx, gc* ngc) {
|
buffer.str() = temp_buffer;
|
||||||
auto local = ctx->localr;
|
buffer.val.gcobj->unmutable = true;
|
||||||
auto file_descriptor = local[1];
|
delete []temp_buffer;
|
||||||
auto source = local[2];
|
return var::num(read_size);
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
}
|
||||||
return nas_err("io::write", "not a valid filehandle");
|
|
||||||
}
|
var builtin_write(context* ctx, gc* ngc) {
|
||||||
if (!source.is_str()) {
|
auto local = ctx->localr;
|
||||||
return nas_err("io::write", "\"str\" must be string");
|
auto file_descriptor = local[1];
|
||||||
}
|
auto source = local[2];
|
||||||
return var::num(static_cast<f64>(fwrite(
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
source.str().c_str(), 1, source.str().length(),
|
return nas_err("io::write", "not a valid filehandle");
|
||||||
static_cast<FILE*>(file_descriptor.ghost().pointer)
|
}
|
||||||
)));
|
if (!source.is_str()) {
|
||||||
}
|
return nas_err("io::write", "\"str\" must be string");
|
||||||
|
}
|
||||||
var builtin_seek(context* ctx, gc* ngc) {
|
return var::num(static_cast<f64>(fwrite(
|
||||||
auto local = ctx->localr;
|
source.str().c_str(), 1, source.str().length(),
|
||||||
auto file_descriptor = local[1];
|
static_cast<FILE*>(file_descriptor.ghost().pointer)
|
||||||
auto position = local[2];
|
)));
|
||||||
auto whence = local[3];
|
}
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
|
||||||
return nas_err("io::seek", "not a valid filehandle");
|
var builtin_seek(context* ctx, gc* ngc) {
|
||||||
}
|
auto local = ctx->localr;
|
||||||
return var::num(static_cast<f64>(fseek(
|
auto file_descriptor = local[1];
|
||||||
static_cast<FILE*>(file_descriptor.ghost().pointer),
|
auto position = local[2];
|
||||||
position.num(),
|
auto whence = local[3];
|
||||||
whence.num()
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
)));
|
return nas_err("io::seek", "not a valid filehandle");
|
||||||
}
|
}
|
||||||
|
return var::num(static_cast<f64>(fseek(
|
||||||
var builtin_tell(context* ctx, gc* ngc) {
|
static_cast<FILE*>(file_descriptor.ghost().pointer),
|
||||||
auto file_descriptor = ctx->localr[1];
|
position.num(),
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
whence.num()
|
||||||
return nas_err("io::tell", "not a valid filehandle");
|
)));
|
||||||
}
|
}
|
||||||
return var::num(static_cast<f64>(
|
|
||||||
ftell(static_cast<FILE*>(file_descriptor.ghost().pointer))
|
var builtin_tell(context* ctx, gc* ngc) {
|
||||||
));
|
auto file_descriptor = ctx->localr[1];
|
||||||
}
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
|
return nas_err("io::tell", "not a valid filehandle");
|
||||||
var builtin_readln(context* ctx, gc* ngc) {
|
}
|
||||||
auto file_descriptor = ctx->localr[1];
|
return var::num(static_cast<f64>(
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
ftell(static_cast<FILE*>(file_descriptor.ghost().pointer))
|
||||||
return nas_err("io::readln", "not a valid filehandle");
|
));
|
||||||
}
|
}
|
||||||
auto result = ngc->alloc(vm_type::vm_str);
|
|
||||||
char c;
|
var builtin_readln(context* ctx, gc* ngc) {
|
||||||
while((c = fgetc(static_cast<FILE*>(file_descriptor.ghost().pointer)))!=EOF) {
|
auto file_descriptor = ctx->localr[1];
|
||||||
if (c=='\r') {
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
continue;
|
return nas_err("io::readln", "not a valid filehandle");
|
||||||
}
|
}
|
||||||
if (c=='\n') {
|
auto result = ngc->alloc(vm_type::vm_str);
|
||||||
return result;
|
char c;
|
||||||
}
|
while((c = fgetc(static_cast<FILE*>(file_descriptor.ghost().pointer)))!=EOF) {
|
||||||
result.str().push_back(c);
|
if (c=='\r') {
|
||||||
}
|
continue;
|
||||||
if (result.str().length()) {
|
}
|
||||||
return result;
|
if (c=='\n') {
|
||||||
}
|
return result;
|
||||||
return nil;
|
}
|
||||||
}
|
result.str().push_back(c);
|
||||||
|
}
|
||||||
var builtin_stat(context* ctx, gc* ngc) {
|
if (result.str().length()) {
|
||||||
auto name = ctx->localr[1];
|
return result;
|
||||||
if (!name.is_str()) {
|
}
|
||||||
return nas_err("io::stat", "\"filename\" must be string");
|
return nil;
|
||||||
}
|
}
|
||||||
struct stat buffer;
|
|
||||||
if (stat(name.str().c_str(), &buffer)<0) {
|
var builtin_stat(context* ctx, gc* ngc) {
|
||||||
return nas_err("io::stat", "failed to open file <" + name.str() + ">");
|
auto name = ctx->localr[1];
|
||||||
}
|
if (!name.is_str()) {
|
||||||
auto result = ngc->alloc(vm_type::vm_vec);
|
return nas_err("io::stat", "\"filename\" must be string");
|
||||||
result.vec().elems = {
|
}
|
||||||
var::num(static_cast<f64>(buffer.st_dev)),
|
struct stat buffer;
|
||||||
var::num(static_cast<f64>(buffer.st_ino)),
|
if (stat(name.str().c_str(), &buffer)<0) {
|
||||||
var::num(static_cast<f64>(buffer.st_mode)),
|
return nas_err("io::stat", "failed to open file <" + name.str() + ">");
|
||||||
var::num(static_cast<f64>(buffer.st_nlink)),
|
}
|
||||||
var::num(static_cast<f64>(buffer.st_uid)),
|
auto result = ngc->alloc(vm_type::vm_vec);
|
||||||
var::num(static_cast<f64>(buffer.st_gid)),
|
result.vec().elems = {
|
||||||
var::num(static_cast<f64>(buffer.st_rdev)),
|
var::num(static_cast<f64>(buffer.st_dev)),
|
||||||
var::num(static_cast<f64>(buffer.st_size)),
|
var::num(static_cast<f64>(buffer.st_ino)),
|
||||||
var::num(static_cast<f64>(buffer.st_atime)),
|
var::num(static_cast<f64>(buffer.st_mode)),
|
||||||
var::num(static_cast<f64>(buffer.st_mtime)),
|
var::num(static_cast<f64>(buffer.st_nlink)),
|
||||||
var::num(static_cast<f64>(buffer.st_ctime))
|
var::num(static_cast<f64>(buffer.st_uid)),
|
||||||
};
|
var::num(static_cast<f64>(buffer.st_gid)),
|
||||||
return result;
|
var::num(static_cast<f64>(buffer.st_rdev)),
|
||||||
}
|
var::num(static_cast<f64>(buffer.st_size)),
|
||||||
|
var::num(static_cast<f64>(buffer.st_atime)),
|
||||||
var builtin_eof(context* ctx, gc* ngc) {
|
var::num(static_cast<f64>(buffer.st_mtime)),
|
||||||
auto file_descriptor = ctx->localr[1];
|
var::num(static_cast<f64>(buffer.st_ctime))
|
||||||
if (!file_descriptor.object_check(file_type_name)) {
|
};
|
||||||
return nas_err("io::readln", "not a valid filehandle");
|
return result;
|
||||||
}
|
}
|
||||||
return var::num(static_cast<f64>(
|
|
||||||
feof(static_cast<FILE*>(file_descriptor.ghost().pointer))
|
var builtin_eof(context* ctx, gc* ngc) {
|
||||||
));
|
auto file_descriptor = ctx->localr[1];
|
||||||
}
|
if (!file_descriptor.object_check(file_type_name)) {
|
||||||
|
return nas_err("io::readln", "not a valid filehandle");
|
||||||
var builtin_stdin(context* ctx, gc* ngc) {
|
}
|
||||||
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
return var::num(static_cast<f64>(
|
||||||
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stdin);
|
feof(static_cast<FILE*>(file_descriptor.ghost().pointer))
|
||||||
return file_descriptor;
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin_stdout(context* ctx, gc* ngc) {
|
var builtin_stdin(context* ctx, gc* ngc) {
|
||||||
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
||||||
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stdout);
|
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stdin);
|
||||||
return file_descriptor;
|
return file_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin_stderr(context* ctx, gc* ngc) {
|
var builtin_stdout(context* ctx, gc* ngc) {
|
||||||
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
||||||
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stderr);
|
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stdout);
|
||||||
return file_descriptor;
|
return file_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var builtin_stderr(context* ctx, gc* ngc) {
|
||||||
nasal_builtin_table io_lib_native[] = {
|
auto file_descriptor = ngc->alloc(vm_type::vm_ghost);
|
||||||
{"__readfile", builtin_readfile},
|
file_descriptor.ghost().set(file_type_name, nullptr, nullptr, stderr);
|
||||||
{"__fout", builtin_fout},
|
return file_descriptor;
|
||||||
{"__exists", builtin_exists},
|
}
|
||||||
{"__open", builtin_open},
|
|
||||||
{"__close", builtin_close},
|
|
||||||
{"__read", builtin_read},
|
nasal_builtin_table io_lib_native[] = {
|
||||||
{"__write", builtin_write},
|
{"__readfile", builtin_readfile},
|
||||||
{"__seek", builtin_seek},
|
{"__fout", builtin_fout},
|
||||||
{"__tell", builtin_tell},
|
{"__exists", builtin_exists},
|
||||||
{"__readln", builtin_readln},
|
{"__open", builtin_open},
|
||||||
{"__stat", builtin_stat},
|
{"__close", builtin_close},
|
||||||
{"__eof", builtin_eof},
|
{"__read", builtin_read},
|
||||||
{"__stdin", builtin_stdin},
|
{"__write", builtin_write},
|
||||||
{"__stdout", builtin_stdout},
|
{"__seek", builtin_seek},
|
||||||
{"__stderr", builtin_stderr},
|
{"__tell", builtin_tell},
|
||||||
{nullptr, nullptr}
|
{"__readln", builtin_readln},
|
||||||
};
|
{"__stat", builtin_stat},
|
||||||
|
{"__eof", builtin_eof},
|
||||||
}
|
{"__stdin", builtin_stdin},
|
||||||
|
{"__stdout", builtin_stdout},
|
||||||
|
{"__stderr", builtin_stderr},
|
||||||
|
{nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
76
src/io_lib.h
76
src/io_lib.h
|
@ -1,41 +1,35 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "nasal.h"
|
#include "nasal.h"
|
||||||
#include "nasal_gc.h"
|
#include "nasal_gc.h"
|
||||||
#include "nasal_builtin.h"
|
#include "nasal_builtin.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#ifndef _MSC_VER
|
||||||
|
#include <unistd.h>
|
||||||
#ifndef _MSC_VER
|
#else
|
||||||
#include <unistd.h>
|
#include <io.h>
|
||||||
#else
|
#endif
|
||||||
#include <io.h>
|
|
||||||
#endif
|
namespace nasal {
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
void filehandle_destructor(void*);
|
||||||
#define F_OK 0 // fuck msc
|
|
||||||
#endif
|
var builtin_readfile(context*, gc*);
|
||||||
|
var builtin_fout(context*, gc*);
|
||||||
namespace nasal {
|
var builtin_exists(context*, gc*);
|
||||||
|
var builtin_open(context*, gc*);
|
||||||
void filehandle_destructor(void*);
|
var builtin_close(context*, gc*);
|
||||||
|
var builtin_read(context*, gc*);
|
||||||
var builtin_readfile(context*, gc*);
|
var builtin_write(context*, gc*);
|
||||||
var builtin_fout(context*, gc*);
|
var builtin_seek(context*, gc*);
|
||||||
var builtin_exists(context*, gc*);
|
var builtin_tell(context*, gc*);
|
||||||
var builtin_open(context*, gc*);
|
var builtin_readln(context*, gc*);
|
||||||
var builtin_close(context*, gc*);
|
var builtin_stat(context*, gc*);
|
||||||
var builtin_read(context*, gc*);
|
var builtin_eof(context*, gc*);
|
||||||
var builtin_write(context*, gc*);
|
var builtin_stdin(context*, gc*);
|
||||||
var builtin_seek(context*, gc*);
|
var builtin_stdout(context*, gc*);
|
||||||
var builtin_tell(context*, gc*);
|
var builtin_stderr(context*, gc*);
|
||||||
var builtin_readln(context*, gc*);
|
|
||||||
var builtin_stat(context*, gc*);
|
extern nasal_builtin_table io_lib_native[];
|
||||||
var builtin_eof(context*, gc*);
|
|
||||||
var builtin_stdin(context*, gc*);
|
}
|
||||||
var builtin_stdout(context*, gc*);
|
|
||||||
var builtin_stderr(context*, gc*);
|
|
||||||
|
|
||||||
extern nasal_builtin_table io_lib_native[];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,399 +1,403 @@
|
||||||
#include "nasal_import.h"
|
#include "nasal_import.h"
|
||||||
#include "symbol_finder.h"
|
#include "symbol_finder.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace nasal {
|
#ifdef _MSC_VER
|
||||||
|
#define F_OK 0 // fuck msc
|
||||||
linker::linker(): show_path_flag(false), library_loaded(false), this_file("") {
|
#endif
|
||||||
const auto seperator= is_windows()? ';':':';
|
|
||||||
const auto PATH = std::string(getenv("PATH"));
|
namespace nasal {
|
||||||
usize last = 0, position = PATH.find(seperator, 0);
|
|
||||||
while(position!=std::string::npos) {
|
linker::linker(): show_path_flag(false), library_loaded(false), this_file("") {
|
||||||
std::string dirpath = PATH.substr(last, position-last);
|
const auto seperator= is_windows()? ';':':';
|
||||||
if (dirpath.length()) {
|
const auto PATH = std::string(getenv("PATH"));
|
||||||
envpath.push_back(dirpath);
|
usize last = 0, position = PATH.find(seperator, 0);
|
||||||
}
|
while(position!=std::string::npos) {
|
||||||
last = position+1;
|
std::string dirpath = PATH.substr(last, position-last);
|
||||||
position = PATH.find(seperator, last);
|
if (dirpath.length()) {
|
||||||
}
|
envpath.push_back(dirpath);
|
||||||
if (last!=PATH.length()) {
|
}
|
||||||
envpath.push_back(PATH.substr(last));
|
last = position+1;
|
||||||
}
|
position = PATH.find(seperator, last);
|
||||||
}
|
}
|
||||||
|
if (last!=PATH.length()) {
|
||||||
std::string linker::get_path(expr* node) {
|
envpath.push_back(PATH.substr(last));
|
||||||
if (node->get_type()==expr_type::ast_use) {
|
}
|
||||||
auto file_relative_path = std::string("");
|
}
|
||||||
const auto& path = reinterpret_cast<use_stmt*>(node)->get_path();
|
|
||||||
for(auto i : path) {
|
std::string linker::get_path(expr* node) {
|
||||||
file_relative_path += i->get_name();
|
if (node->get_type()==expr_type::ast_use) {
|
||||||
if (i!=path.back()) {
|
auto file_relative_path = std::string("");
|
||||||
file_relative_path += (is_windows()? "\\":"/");
|
const auto& path = reinterpret_cast<use_stmt*>(node)->get_path();
|
||||||
}
|
for(auto i : path) {
|
||||||
}
|
file_relative_path += i->get_name();
|
||||||
return file_relative_path + ".nas";
|
if (i!=path.back()) {
|
||||||
}
|
file_relative_path += (is_windows()? "\\":"/");
|
||||||
auto call_node = reinterpret_cast<call_expr*>(node);
|
}
|
||||||
auto arguments = reinterpret_cast<call_function*>(call_node->get_calls()[0]);
|
}
|
||||||
auto content = reinterpret_cast<string_literal*>(arguments->get_argument()[0]);
|
return file_relative_path + ".nas";
|
||||||
return content->get_content();
|
}
|
||||||
}
|
auto call_node = reinterpret_cast<call_expr*>(node);
|
||||||
|
auto arguments = reinterpret_cast<call_function*>(call_node->get_calls()[0]);
|
||||||
std::string linker::find_real_file_path(
|
auto content = reinterpret_cast<string_literal*>(arguments->get_argument()[0]);
|
||||||
const std::string& filename, const span& location) {
|
return content->get_content();
|
||||||
// first add file name itself into the file path
|
}
|
||||||
std::vector<std::string> path_list = {filename};
|
|
||||||
|
std::string linker::find_real_file_path(
|
||||||
// generate search path from environ path
|
const std::string& filename, const span& location) {
|
||||||
for(const auto& p : envpath) {
|
// first add file name itself into the file path
|
||||||
path_list.push_back(p + (is_windows()? "\\":"/") + filename);
|
std::vector<std::string> path_list = {filename};
|
||||||
}
|
|
||||||
|
// generate search path from environ path
|
||||||
// search file
|
for(const auto& p : envpath) {
|
||||||
for(const auto& path : path_list) {
|
path_list.push_back(p + (is_windows()? "\\":"/") + filename);
|
||||||
if (access(path.c_str(), F_OK)!=-1) {
|
}
|
||||||
return path;
|
|
||||||
}
|
// search file
|
||||||
}
|
for(const auto& path : path_list) {
|
||||||
|
if (access(path.c_str(), F_OK)!=-1) {
|
||||||
// we will find lib.nas in nasal std directory
|
return path;
|
||||||
if (filename=="lib.nas") {
|
}
|
||||||
return is_windows()?
|
}
|
||||||
find_real_file_path("std\\lib.nas", location):
|
|
||||||
find_real_file_path("std/lib.nas", location);
|
// we will find lib.nas in nasal std directory
|
||||||
}
|
if (filename=="lib.nas") {
|
||||||
if (!show_path_flag) {
|
return is_windows()?
|
||||||
err.err("link",
|
find_real_file_path("std\\lib.nas", location):
|
||||||
"in <" + location.file + ">: " +
|
find_real_file_path("std/lib.nas", location);
|
||||||
"cannot find file <" + filename + ">, " +
|
}
|
||||||
"use <-d> to get detail search path"
|
if (!show_path_flag) {
|
||||||
);
|
err.err("link",
|
||||||
return "";
|
"in <" + location.file + ">: " +
|
||||||
}
|
"cannot find file <" + filename + ">, " +
|
||||||
auto path_list_info = std::string("");
|
"use <-d> to get detail search path"
|
||||||
for(const auto& path : path_list) {
|
);
|
||||||
path_list_info += " -> " + path + "\n";
|
return "";
|
||||||
}
|
}
|
||||||
err.err("link",
|
auto path_list_info = std::string("");
|
||||||
"in <" + location.file + ">: " +
|
for(const auto& path : path_list) {
|
||||||
"cannot find file <" + filename +
|
path_list_info += " -> " + path + "\n";
|
||||||
"> in these paths:\n" + path_list_info
|
}
|
||||||
);
|
err.err("link",
|
||||||
return "";
|
"in <" + location.file + ">: " +
|
||||||
}
|
"cannot find file <" + filename +
|
||||||
|
"> in these paths:\n" + path_list_info
|
||||||
bool linker::import_check(expr* node) {
|
);
|
||||||
if (node->get_type()==expr_type::ast_use) {
|
return "";
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
/*
|
bool linker::import_check(expr* node) {
|
||||||
call
|
if (node->get_type()==expr_type::ast_use) {
|
||||||
|_id:import
|
return true;
|
||||||
|_call_func
|
}
|
||||||
|_string:'filename'
|
/*
|
||||||
*/
|
call
|
||||||
if (node->get_type()!=expr_type::ast_call) {
|
|_id:import
|
||||||
return false;
|
|_call_func
|
||||||
}
|
|_string:'filename'
|
||||||
auto call_node = reinterpret_cast<call_expr*>(node);
|
*/
|
||||||
auto first_expr = call_node->get_first();
|
if (node->get_type()!=expr_type::ast_call) {
|
||||||
if (first_expr->get_type()!=expr_type::ast_id) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
auto call_node = reinterpret_cast<call_expr*>(node);
|
||||||
if (reinterpret_cast<identifier*>(first_expr)->get_name()!="import") {
|
auto first_expr = call_node->get_first();
|
||||||
return false;
|
if (first_expr->get_type()!=expr_type::ast_id) {
|
||||||
}
|
return false;
|
||||||
if (!call_node->get_calls().size()) {
|
}
|
||||||
return false;
|
if (reinterpret_cast<identifier*>(first_expr)->get_name()!="import") {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
// import("xxx");
|
if (!call_node->get_calls().size()) {
|
||||||
if (call_node->get_calls().size()!=1) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
auto maybe_func_call = call_node->get_calls()[0];
|
// import("xxx");
|
||||||
if (maybe_func_call->get_type()!=expr_type::ast_callf) {
|
if (call_node->get_calls().size()!=1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto func_call = reinterpret_cast<call_function*>(maybe_func_call);
|
auto maybe_func_call = call_node->get_calls()[0];
|
||||||
if (func_call->get_argument().size()!=1) {
|
if (maybe_func_call->get_type()!=expr_type::ast_callf) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (func_call->get_argument()[0]->get_type()!=expr_type::ast_str) {
|
auto func_call = reinterpret_cast<call_function*>(maybe_func_call);
|
||||||
return false;
|
if (func_call->get_argument().size()!=1) {
|
||||||
}
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
if (func_call->get_argument()[0]->get_type()!=expr_type::ast_str) {
|
||||||
|
return false;
|
||||||
bool linker::check_exist_or_record_file(const std::string& file) {
|
}
|
||||||
// avoid importing the same file
|
return true;
|
||||||
for(const auto& name : imported_files) {
|
}
|
||||||
if (file==name) {
|
|
||||||
return true;
|
bool linker::check_exist_or_record_file(const std::string& file) {
|
||||||
}
|
// avoid importing the same file
|
||||||
}
|
for(const auto& name : imported_files) {
|
||||||
imported_files.push_back(file);
|
if (file==name) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
bool linker::check_self_import(const std::string& file) {
|
imported_files.push_back(file);
|
||||||
for(const auto& name : module_load_stack) {
|
return false;
|
||||||
if (file==name) {
|
}
|
||||||
return true;
|
|
||||||
}
|
bool linker::check_self_import(const std::string& file) {
|
||||||
}
|
for(const auto& name : module_load_stack) {
|
||||||
return false;
|
if (file==name) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
std::string linker::generate_self_import_path(const std::string& filename) {
|
}
|
||||||
std::string res = "";
|
return false;
|
||||||
for(const auto& i : module_load_stack) {
|
}
|
||||||
res += "[" + i + "] -> ";
|
|
||||||
}
|
std::string linker::generate_self_import_path(const std::string& filename) {
|
||||||
return res + "[" + filename + "]";
|
std::string res = "";
|
||||||
}
|
for(const auto& i : module_load_stack) {
|
||||||
|
res += "[" + i + "] -> ";
|
||||||
void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
|
}
|
||||||
// add children of add_root to the back of root
|
return res + "[" + filename + "]";
|
||||||
for(auto& i : old_tree_root->get_expressions()) {
|
}
|
||||||
new_tree_root->add_expression(i);
|
|
||||||
}
|
void linker::link(code_block* new_tree_root, code_block* old_tree_root) {
|
||||||
// clean old root
|
// add children of add_root to the back of root
|
||||||
old_tree_root->get_expressions().clear();
|
for(auto& i : old_tree_root->get_expressions()) {
|
||||||
}
|
new_tree_root->add_expression(i);
|
||||||
|
}
|
||||||
code_block* linker::import_regular_file(
|
// clean old root
|
||||||
expr* node, std::unordered_set<std::string>& used_modules) {
|
old_tree_root->get_expressions().clear();
|
||||||
// get filename
|
}
|
||||||
auto filename = get_path(node);
|
|
||||||
|
code_block* linker::import_regular_file(
|
||||||
// avoid infinite loading loop
|
expr* node, std::unordered_set<std::string>& used_modules) {
|
||||||
filename = find_real_file_path(filename, node->get_location());
|
// get filename
|
||||||
// if get empty string(error) or this file is used before, do not parse
|
auto filename = get_path(node);
|
||||||
if (!filename.length() || used_modules.count(filename)) {
|
|
||||||
return new code_block({0, 0, 0, 0, filename});
|
// avoid infinite loading loop
|
||||||
}
|
filename = find_real_file_path(filename, node->get_location());
|
||||||
|
// if get empty string(error) or this file is used before, do not parse
|
||||||
// check self import, avoid infinite loading loop
|
if (!filename.length() || used_modules.count(filename)) {
|
||||||
if (check_self_import(filename)) {
|
return new code_block({0, 0, 0, 0, filename});
|
||||||
err.err("link",
|
}
|
||||||
"self-referenced module <" + filename + ">:\n" +
|
|
||||||
" reference path: " + generate_self_import_path(filename)
|
// check self import, avoid infinite loading loop
|
||||||
);
|
if (check_self_import(filename)) {
|
||||||
return new code_block({0, 0, 0, 0, filename});
|
err.err("link",
|
||||||
}
|
"self-referenced module <" + filename + ">:\n" +
|
||||||
check_exist_or_record_file(filename);
|
" reference path: " + generate_self_import_path(filename)
|
||||||
|
);
|
||||||
module_load_stack.push_back(filename);
|
return new code_block({0, 0, 0, 0, filename});
|
||||||
// start importing...
|
}
|
||||||
lexer nasal_lexer;
|
check_exist_or_record_file(filename);
|
||||||
parse nasal_parser;
|
|
||||||
if (nasal_lexer.scan(filename).geterr()) {
|
module_load_stack.push_back(filename);
|
||||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
// start importing...
|
||||||
return new code_block({0, 0, 0, 0, filename});
|
lexer nasal_lexer;
|
||||||
}
|
parse nasal_parser;
|
||||||
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
if (nasal_lexer.scan(filename).geterr()) {
|
||||||
err.err("link", "error occurred when analysing <" + filename + ">");
|
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||||
return new code_block({0, 0, 0, 0, filename});
|
return new code_block({0, 0, 0, 0, filename});
|
||||||
}
|
}
|
||||||
// swap result out
|
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
||||||
auto parse_result = nasal_parser.swap(nullptr);
|
err.err("link", "error occurred when analysing <" + filename + ">");
|
||||||
|
return new code_block({0, 0, 0, 0, filename});
|
||||||
// check if parse result has 'import'
|
}
|
||||||
auto result = load(parse_result, filename);
|
// swap result out
|
||||||
module_load_stack.pop_back();
|
auto parse_result = nasal_parser.swap(nullptr);
|
||||||
return result;
|
|
||||||
}
|
// check if parse result has 'import'
|
||||||
|
auto result = load(parse_result, filename);
|
||||||
code_block* linker::import_nasal_lib() {
|
module_load_stack.pop_back();
|
||||||
auto path = find_real_file_path(
|
return result;
|
||||||
"lib.nas", {0, 0, 0, 0, this_file}
|
}
|
||||||
);
|
|
||||||
if (!path.length()) {
|
code_block* linker::import_nasal_lib() {
|
||||||
return new code_block({0, 0, 0, 0, path});
|
auto path = find_real_file_path(
|
||||||
}
|
"lib.nas", {0, 0, 0, 0, this_file}
|
||||||
|
);
|
||||||
// avoid infinite loading library
|
if (!path.length()) {
|
||||||
if (check_exist_or_record_file(path)) {
|
return new code_block({0, 0, 0, 0, path});
|
||||||
return new code_block({0, 0, 0, 0, path});
|
}
|
||||||
}
|
|
||||||
|
// avoid infinite loading library
|
||||||
// start importing...
|
if (check_exist_or_record_file(path)) {
|
||||||
lexer nasal_lexer;
|
return new code_block({0, 0, 0, 0, path});
|
||||||
parse nasal_parser;
|
}
|
||||||
if (nasal_lexer.scan(path).geterr()) {
|
|
||||||
err.err("link",
|
// start importing...
|
||||||
"error occurred when analysing library <" + path + ">"
|
lexer nasal_lexer;
|
||||||
);
|
parse nasal_parser;
|
||||||
return new code_block({0, 0, 0, 0, path});
|
if (nasal_lexer.scan(path).geterr()) {
|
||||||
}
|
err.err("link",
|
||||||
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
"error occurred when analysing library <" + path + ">"
|
||||||
err.err("link",
|
);
|
||||||
"error occurred when analysing library <" + path + ">"
|
return new code_block({0, 0, 0, 0, path});
|
||||||
);
|
}
|
||||||
return new code_block({0, 0, 0, 0, path});
|
if (nasal_parser.compile(nasal_lexer).geterr()) {
|
||||||
}
|
err.err("link",
|
||||||
// swap result out
|
"error occurred when analysing library <" + path + ">"
|
||||||
auto parse_result = nasal_parser.swap(nullptr);
|
);
|
||||||
// check if library has 'import' (in fact it should not)
|
return new code_block({0, 0, 0, 0, path});
|
||||||
return load(parse_result, path);
|
}
|
||||||
}
|
// swap result out
|
||||||
|
auto parse_result = nasal_parser.swap(nullptr);
|
||||||
std::string linker::generate_module_name(const std::string& file_path) {
|
// check if library has 'import' (in fact it should not)
|
||||||
auto error_name = "module@[" + file_path + "]";
|
return load(parse_result, path);
|
||||||
if (!file_path.length()) {
|
}
|
||||||
return error_name;
|
|
||||||
}
|
std::string linker::generate_module_name(const std::string& file_path) {
|
||||||
|
auto error_name = "module@[" + file_path + "]";
|
||||||
// check file suffix and get file suffix position
|
if (!file_path.length()) {
|
||||||
auto suffix_position = file_path.find(".nas");
|
return error_name;
|
||||||
if (suffix_position==std::string::npos) {
|
}
|
||||||
err.warn("link",
|
|
||||||
"get invalid module name from <" + file_path + ">, " +
|
// check file suffix and get file suffix position
|
||||||
"will not be easily accessed. " +
|
auto suffix_position = file_path.find(".nas");
|
||||||
"\".nas\" suffix is required."
|
if (suffix_position==std::string::npos) {
|
||||||
);
|
err.warn("link",
|
||||||
return error_name;
|
"get invalid module name from <" + file_path + ">, " +
|
||||||
}
|
"will not be easily accessed. " +
|
||||||
if (suffix_position+4!=file_path.length()) {
|
"\".nas\" suffix is required."
|
||||||
err.warn("link",
|
);
|
||||||
"get invalid module name from <" + file_path + ">, " +
|
return error_name;
|
||||||
"will not be easily accessed. " +
|
}
|
||||||
"only one \".nas\" suffix is required in the path."
|
if (suffix_position+4!=file_path.length()) {
|
||||||
);
|
err.warn("link",
|
||||||
return error_name;
|
"get invalid module name from <" + file_path + ">, " +
|
||||||
}
|
"will not be easily accessed. " +
|
||||||
|
"only one \".nas\" suffix is required in the path."
|
||||||
// only get the file name as module name, directory path is not included
|
);
|
||||||
auto split_position = file_path.find_last_of("/");
|
return error_name;
|
||||||
// find "\\" in windows platform
|
}
|
||||||
if (split_position==std::string::npos) {
|
|
||||||
split_position = file_path.find_last_of("\\");
|
// only get the file name as module name, directory path is not included
|
||||||
}
|
auto split_position = file_path.find_last_of("/");
|
||||||
|
// find "\\" in windows platform
|
||||||
// split file path to get module name
|
if (split_position==std::string::npos) {
|
||||||
auto module_name = split_position==std::string::npos?
|
split_position = file_path.find_last_of("\\");
|
||||||
file_path.substr(0, suffix_position):
|
}
|
||||||
file_path.substr(split_position+1, suffix_position-split_position-1);
|
|
||||||
|
// split file path to get module name
|
||||||
// check validation of module name
|
auto module_name = split_position==std::string::npos?
|
||||||
if (!module_name.length()) {
|
file_path.substr(0, suffix_position):
|
||||||
err.warn("link",
|
file_path.substr(split_position+1, suffix_position-split_position-1);
|
||||||
"get empty module name from <" + file_path + ">, " +
|
|
||||||
"will not be easily accessed."
|
// check validation of module name
|
||||||
);
|
if (!module_name.length()) {
|
||||||
return module_name;
|
err.warn("link",
|
||||||
}
|
"get empty module name from <" + file_path + ">, " +
|
||||||
if (std::isdigit(module_name[0]) ||
|
"will not be easily accessed."
|
||||||
module_name.find(".")!=std::string::npos ||
|
);
|
||||||
module_name.find("-")!=std::string::npos) {
|
return module_name;
|
||||||
err.warn("link",
|
}
|
||||||
"get module <" + module_name + "> from <" + file_path + ">, " +
|
if (std::isdigit(module_name[0]) ||
|
||||||
"will not be easily accessed."
|
module_name.find(".")!=std::string::npos ||
|
||||||
);
|
module_name.find("-")!=std::string::npos) {
|
||||||
}
|
err.warn("link",
|
||||||
return module_name;
|
"get module <" + module_name + "> from <" + file_path + ">, " +
|
||||||
}
|
"will not be easily accessed."
|
||||||
|
);
|
||||||
return_expr* linker::generate_module_return(code_block* block) {
|
}
|
||||||
auto finder = std::unique_ptr<symbol_finder>(new symbol_finder);
|
return module_name;
|
||||||
auto result = new return_expr(block->get_location());
|
}
|
||||||
auto value = new hash_expr(block->get_location());
|
|
||||||
result->set_value(value);
|
return_expr* linker::generate_module_return(code_block* block) {
|
||||||
for(const auto& i : finder->do_find(block)) {
|
auto finder = std::unique_ptr<symbol_finder>(new symbol_finder);
|
||||||
auto pair = new hash_pair(block->get_location());
|
auto result = new return_expr(block->get_location());
|
||||||
// do not export symbol begins with '_'
|
auto value = new hash_expr(block->get_location());
|
||||||
if (i.name.length() && i.name[0]=='_') {
|
result->set_value(value);
|
||||||
continue;
|
for(const auto& i : finder->do_find(block)) {
|
||||||
}
|
auto pair = new hash_pair(block->get_location());
|
||||||
pair->set_name(i.name);
|
// do not export symbol begins with '_'
|
||||||
pair->set_value(new identifier(block->get_location(), i.name));
|
if (i.name.length() && i.name[0]=='_') {
|
||||||
value->add_member(pair);
|
continue;
|
||||||
}
|
}
|
||||||
return result;
|
pair->set_name(i.name);
|
||||||
}
|
pair->set_value(new identifier(block->get_location(), i.name));
|
||||||
|
value->add_member(pair);
|
||||||
definition_expr* linker::generate_module_definition(code_block* block) {
|
}
|
||||||
auto def = new definition_expr(block->get_location());
|
return result;
|
||||||
def->set_identifier(new identifier(
|
}
|
||||||
block->get_location(),
|
|
||||||
generate_module_name(block->get_location().file)
|
definition_expr* linker::generate_module_definition(code_block* block) {
|
||||||
));
|
auto def = new definition_expr(block->get_location());
|
||||||
|
def->set_identifier(new identifier(
|
||||||
auto call = new call_expr(block->get_location());
|
block->get_location(),
|
||||||
auto func = new function(block->get_location());
|
generate_module_name(block->get_location().file)
|
||||||
func->set_code_block(block);
|
));
|
||||||
func->get_code_block()->add_expression(generate_module_return(block));
|
|
||||||
call->set_first(func);
|
auto call = new call_expr(block->get_location());
|
||||||
call->add_call(new call_function(block->get_location()));
|
auto func = new function(block->get_location());
|
||||||
|
func->set_code_block(block);
|
||||||
def->set_value(call);
|
func->get_code_block()->add_expression(generate_module_return(block));
|
||||||
return def;
|
call->set_first(func);
|
||||||
}
|
call->add_call(new call_function(block->get_location()));
|
||||||
|
|
||||||
code_block* linker::load(code_block* program_root, const std::string& filename) {
|
def->set_value(call);
|
||||||
auto tree = new code_block({0, 0, 0, 0, filename});
|
return def;
|
||||||
// load library, this ast will be linked with root directly
|
}
|
||||||
// so no extra namespace is generated
|
|
||||||
if (!library_loaded) {
|
code_block* linker::load(code_block* program_root, const std::string& filename) {
|
||||||
auto nasal_lib_code_block = import_nasal_lib();
|
auto tree = new code_block({0, 0, 0, 0, filename});
|
||||||
// insert nasal lib code to the back of tree
|
// load library, this ast will be linked with root directly
|
||||||
link(tree, nasal_lib_code_block);
|
// so no extra namespace is generated
|
||||||
delete nasal_lib_code_block;
|
if (!library_loaded) {
|
||||||
library_loaded = true;
|
auto nasal_lib_code_block = import_nasal_lib();
|
||||||
}
|
// insert nasal lib code to the back of tree
|
||||||
|
link(tree, nasal_lib_code_block);
|
||||||
// load imported modules
|
delete nasal_lib_code_block;
|
||||||
std::unordered_set<std::string> used_modules = {};
|
library_loaded = true;
|
||||||
for(auto& import_node : program_root->get_expressions()) {
|
}
|
||||||
if (!import_check(import_node)) {
|
|
||||||
break;
|
// load imported modules
|
||||||
}
|
std::unordered_set<std::string> used_modules = {};
|
||||||
// parse file and get ast
|
for(auto& import_node : program_root->get_expressions()) {
|
||||||
auto module_code_block = import_regular_file(import_node, used_modules);
|
if (!import_check(import_node)) {
|
||||||
auto replace_node = new null_expr(import_node->get_location());
|
break;
|
||||||
// after importing the regular file as module, delete this node
|
}
|
||||||
delete import_node;
|
// parse file and get ast
|
||||||
// and replace the node with null_expr node
|
auto module_code_block = import_regular_file(import_node, used_modules);
|
||||||
import_node = replace_node;
|
auto replace_node = new null_expr(import_node->get_location());
|
||||||
|
// after importing the regular file as module, delete this node
|
||||||
// avoid repeatedly importing the same module
|
delete import_node;
|
||||||
const auto& module_path = module_code_block->get_location().file;
|
// and replace the node with null_expr node
|
||||||
if (used_modules.count(module_path)) {
|
import_node = replace_node;
|
||||||
delete module_code_block;
|
|
||||||
continue;
|
// avoid repeatedly importing the same module
|
||||||
}
|
const auto& module_path = module_code_block->get_location().file;
|
||||||
|
if (used_modules.count(module_path)) {
|
||||||
// then we generate a function warping the code block,
|
delete module_code_block;
|
||||||
// and export the necessary global symbols in this code block
|
continue;
|
||||||
// by generate a return statement, with a hashmap return value
|
}
|
||||||
used_modules.insert(module_path);
|
|
||||||
tree->add_expression(generate_module_definition(module_code_block));
|
// then we generate a function warping the code block,
|
||||||
}
|
// and export the necessary global symbols in this code block
|
||||||
|
// by generate a return statement, with a hashmap return value
|
||||||
// insert program root to the back of tree
|
used_modules.insert(module_path);
|
||||||
link(tree, program_root);
|
tree->add_expression(generate_module_definition(module_code_block));
|
||||||
return tree;
|
}
|
||||||
}
|
|
||||||
|
// insert program root to the back of tree
|
||||||
const error& linker::link(
|
link(tree, program_root);
|
||||||
parse& parse, const std::string& self, bool spath = false) {
|
return tree;
|
||||||
// switch for showing path when errors occur
|
}
|
||||||
show_path_flag = spath;
|
|
||||||
|
const error& linker::link(
|
||||||
// initializing file map
|
parse& parse, const std::string& self, bool spath = false) {
|
||||||
this_file = self;
|
// switch for showing path when errors occur
|
||||||
imported_files = {self};
|
show_path_flag = spath;
|
||||||
module_load_stack = {self};
|
|
||||||
|
// initializing file map
|
||||||
// scan root and import files
|
this_file = self;
|
||||||
// then generate a new ast and return to import_ast
|
imported_files = {self};
|
||||||
auto new_tree_root = load(parse.tree(), self);
|
module_load_stack = {self};
|
||||||
auto old_tree_root = parse.swap(new_tree_root);
|
|
||||||
delete old_tree_root;
|
// scan root and import files
|
||||||
return err;
|
// then generate a new ast and return to import_ast
|
||||||
}
|
auto new_tree_root = load(parse.tree(), self);
|
||||||
|
auto old_tree_root = parse.swap(new_tree_root);
|
||||||
}
|
delete old_tree_root;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,59 +1,55 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#else
|
#else
|
||||||
#define _CRT_SECURE_NO_DEPRECATE 1
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
#define _CRT_NONSTDC_NO_DEPRECATE 1
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#include "nasal.h"
|
||||||
#define F_OK 0
|
#include "nasal_ast.h"
|
||||||
#endif
|
#include "nasal_lexer.h"
|
||||||
|
#include "nasal_parse.h"
|
||||||
#include "nasal.h"
|
#include "symbol_finder.h"
|
||||||
#include "nasal_ast.h"
|
|
||||||
#include "nasal_lexer.h"
|
#include <cstring>
|
||||||
#include "nasal_parse.h"
|
#include <sstream>
|
||||||
#include "symbol_finder.h"
|
#include <vector>
|
||||||
|
#include <unordered_set>
|
||||||
#include <cstring>
|
|
||||||
#include <sstream>
|
namespace nasal {
|
||||||
#include <vector>
|
|
||||||
#include <unordered_set>
|
class linker {
|
||||||
|
private:
|
||||||
namespace nasal {
|
bool show_path_flag;
|
||||||
|
bool library_loaded;
|
||||||
class linker {
|
std::string this_file;
|
||||||
private:
|
error err;
|
||||||
bool show_path_flag;
|
std::vector<std::string> imported_files;
|
||||||
bool library_loaded;
|
std::vector<std::string> module_load_stack;
|
||||||
std::string this_file;
|
std::vector<std::string> envpath;
|
||||||
error err;
|
|
||||||
std::vector<std::string> imported_files;
|
private:
|
||||||
std::vector<std::string> module_load_stack;
|
bool import_check(expr*);
|
||||||
std::vector<std::string> envpath;
|
bool check_exist_or_record_file(const std::string&);
|
||||||
|
bool check_self_import(const std::string&);
|
||||||
private:
|
std::string generate_self_import_path(const std::string&);
|
||||||
bool import_check(expr*);
|
void link(code_block*, code_block*);
|
||||||
bool check_exist_or_record_file(const std::string&);
|
std::string get_path(expr*);
|
||||||
bool check_self_import(const std::string&);
|
std::string find_real_file_path(const std::string&, const span&);
|
||||||
std::string generate_self_import_path(const std::string&);
|
code_block* import_regular_file(expr*, std::unordered_set<std::string>&);
|
||||||
void link(code_block*, code_block*);
|
code_block* import_nasal_lib();
|
||||||
std::string get_path(expr*);
|
std::string generate_module_name(const std::string&);
|
||||||
std::string find_real_file_path(const std::string&, const span&);
|
return_expr* generate_module_return(code_block*);
|
||||||
code_block* import_regular_file(expr*, std::unordered_set<std::string>&);
|
definition_expr* generate_module_definition(code_block*);
|
||||||
code_block* import_nasal_lib();
|
code_block* load(code_block*, const std::string&);
|
||||||
std::string generate_module_name(const std::string&);
|
|
||||||
return_expr* generate_module_return(code_block*);
|
public:
|
||||||
definition_expr* generate_module_definition(code_block*);
|
linker();
|
||||||
code_block* load(code_block*, const std::string&);
|
const error& link(parse&, const std::string&, bool);
|
||||||
|
const auto& get_file_list() const {return imported_files;}
|
||||||
public:
|
};
|
||||||
linker();
|
|
||||||
const error& link(parse&, const std::string&, bool);
|
}
|
||||||
const auto& get_file_list() const {return imported_files;}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,393 +1,396 @@
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning (disable:4244)
|
#pragma warning (disable:4244)
|
||||||
#pragma warning (disable:4267)
|
#pragma warning (disable:4267)
|
||||||
#pragma warning (disable:4102)
|
#pragma warning (disable:4102)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nasal_lexer.h"
|
#include "nasal_lexer.h"
|
||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
bool lexer::skip(char c) {
|
bool lexer::skip(char c) {
|
||||||
return c==' ' || c=='\n' || c=='\t' || c=='\r' || c==0;
|
return c==' ' || c=='\n' || c=='\t' || c=='\r' || c==0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_id(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) {
|
bool lexer::is_hex(char c) {
|
||||||
return std::isxdigit(c);
|
return std::isxdigit(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_oct(char c) {
|
bool lexer::is_oct(char c) {
|
||||||
return '0'<=c && c<='7';
|
return '0'<=c && c<='7';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_dec(char c) {
|
bool lexer::is_dec(char c) {
|
||||||
return std::isdigit(c);
|
return std::isdigit(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_str(char c) {
|
bool lexer::is_str(char c) {
|
||||||
return c=='\'' || c=='\"' || c=='`';
|
return c=='\'' || c=='\"' || c=='`';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_single_opr(char c) {
|
bool lexer::is_single_opr(char c) {
|
||||||
return (
|
return (
|
||||||
c=='(' || c==')' || c=='[' || c==']' ||
|
c=='(' || c==')' || c=='[' || c==']' ||
|
||||||
c=='{' || c=='}' || c==',' || c==';' ||
|
c=='{' || c=='}' || c==',' || c==';' ||
|
||||||
c==':' || c=='?' || c=='`' || c=='@' ||
|
c==':' || c=='?' || c=='`' || c=='@' ||
|
||||||
c=='%' || c=='$' || c=='\\'
|
c=='%' || c=='$' || c=='\\'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lexer::is_calc_opr(char c) {
|
bool lexer::is_calc_opr(char c) {
|
||||||
return (
|
return (
|
||||||
c=='=' || c=='+' || c=='-' || c=='*' ||
|
c=='=' || c=='+' || c=='-' || c=='*' ||
|
||||||
c=='!' || c=='/' || c=='<' || c=='>' ||
|
c=='!' || c=='/' || c=='<' || c=='>' ||
|
||||||
c=='~' || c=='|' || c=='&' || c=='^'
|
c=='~' || c=='|' || c=='&' || c=='^'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer::skip_note() {
|
void lexer::skip_note() {
|
||||||
// avoid note, after this process ptr will point to '\n'
|
// avoid note, after this process ptr will point to '\n'
|
||||||
// so next loop line counter+1
|
// so next loop line counter+1
|
||||||
while(++ptr<res.size() && res[ptr]!='\n') {}
|
while(++ptr<res.size() && res[ptr]!='\n') {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer::err_char() {
|
void lexer::err_char() {
|
||||||
++column;
|
++column;
|
||||||
char c = res[ptr++];
|
char c = res[ptr++];
|
||||||
err.err("lexer",
|
err.err("lexer",
|
||||||
{line, column-1, line, column, filename},
|
{line, column-1, line, column, filename},
|
||||||
"invalid character 0x"+chrhex(c)
|
"invalid character 0x"+chrhex(c)
|
||||||
);
|
);
|
||||||
++invalid_char;
|
++invalid_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lexer::open(const std::string& file) {
|
void lexer::open(const std::string& file) {
|
||||||
if (repl::info::instance()->in_repl_mode &&
|
if (repl::info::instance()->in_repl_mode &&
|
||||||
repl::info::instance()->repl_file_name==file) {
|
repl::info::instance()->repl_file_name==file) {
|
||||||
err.load(file);
|
err.load(file);
|
||||||
filename = file;
|
filename = file;
|
||||||
res = repl::info::instance()->repl_file_source;
|
res = repl::info::instance()->repl_file_source;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check file exsits and it is a regular file
|
// check file exsits and it is a regular file
|
||||||
struct stat buffer;
|
#ifdef _MSC_VER
|
||||||
if (stat(file.c_str(), &buffer)==0 && !S_ISREG(buffer.st_mode)) {
|
#define S_ISREG(m) (((m)&0xF000)==0x8000)
|
||||||
err.err("lexer", "<"+file+"> is not a regular file");
|
#endif
|
||||||
err.chkerr();
|
struct stat buffer;
|
||||||
}
|
if (stat(file.c_str(), &buffer)==0 && !S_ISREG(buffer.st_mode)) {
|
||||||
|
err.err("lexer", "<"+file+"> is not a regular file");
|
||||||
// load
|
err.chkerr();
|
||||||
filename = file;
|
}
|
||||||
std::ifstream in(file, std::ios::binary);
|
|
||||||
if (in.fail()) {
|
// load
|
||||||
err.err("lexer", "failed to open <" + file + ">");
|
filename = file;
|
||||||
res = "";
|
std::ifstream in(file, std::ios::binary);
|
||||||
return;
|
if (in.fail()) {
|
||||||
}
|
err.err("lexer", "failed to open <" + file + ">");
|
||||||
err.load(file);
|
res = "";
|
||||||
std::stringstream ss;
|
return;
|
||||||
ss << in.rdbuf();
|
}
|
||||||
res = ss.str();
|
err.load(file);
|
||||||
}
|
std::stringstream ss;
|
||||||
|
ss << in.rdbuf();
|
||||||
tok lexer::get_type(const std::string& str) {
|
res = ss.str();
|
||||||
return typetbl.count(str)? typetbl.at(str):tok::null;
|
}
|
||||||
}
|
|
||||||
|
tok lexer::get_type(const std::string& str) {
|
||||||
std::string lexer::utf8_gen() {
|
return typetbl.count(str)? typetbl.at(str):tok::null;
|
||||||
std::string str = "";
|
}
|
||||||
while(ptr<res.size() && res[ptr]<0) {
|
|
||||||
std::string tmp = "";
|
std::string lexer::utf8_gen() {
|
||||||
u32 nbytes = utf8_hdchk(res[ptr]);
|
std::string str = "";
|
||||||
if (!nbytes) {
|
while(ptr<res.size() && res[ptr]<0) {
|
||||||
++ptr;
|
std::string tmp = "";
|
||||||
++column;
|
u32 nbytes = utf8_hdchk(res[ptr]);
|
||||||
continue;
|
if (!nbytes) {
|
||||||
}
|
++ptr;
|
||||||
|
++column;
|
||||||
tmp += res[ptr++];
|
continue;
|
||||||
for(u32 i = 0; i<nbytes; ++i, ++ptr) {
|
}
|
||||||
if (ptr<res.size() && (res[ptr]&0xc0)==0x80) {
|
|
||||||
tmp += res[ptr];
|
tmp += res[ptr++];
|
||||||
}
|
for(u32 i = 0; i<nbytes; ++i, ++ptr) {
|
||||||
}
|
if (ptr<res.size() && (res[ptr]&0xc0)==0x80) {
|
||||||
|
tmp += res[ptr];
|
||||||
// utf8 character's total length is 1+nbytes
|
}
|
||||||
if (tmp.length()!=1+nbytes) {
|
}
|
||||||
++column;
|
|
||||||
std::string utf_info = "0x"+chrhex(tmp[0]);
|
// utf8 character's total length is 1+nbytes
|
||||||
for(u32 i = 1; i<tmp.size(); ++i) {
|
if (tmp.length()!=1+nbytes) {
|
||||||
utf_info += " 0x"+chrhex(tmp[i]);
|
++column;
|
||||||
}
|
std::string utf_info = "0x"+chrhex(tmp[0]);
|
||||||
err.err("lexer",
|
for(u32 i = 1; i<tmp.size(); ++i) {
|
||||||
{line, column-1, line, column, filename},
|
utf_info += " 0x"+chrhex(tmp[i]);
|
||||||
"invalid utf-8 <"+utf_info+">"
|
}
|
||||||
);
|
err.err("lexer",
|
||||||
++invalid_char;
|
{line, column-1, line, column, filename},
|
||||||
}
|
"invalid utf-8 <"+utf_info+">"
|
||||||
str += tmp;
|
);
|
||||||
// may have some problems because not all the unicode takes 2 space
|
++invalid_char;
|
||||||
column += 2;
|
}
|
||||||
}
|
str += tmp;
|
||||||
return str;
|
// may have some problems because not all the unicode takes 2 space
|
||||||
}
|
column += 2;
|
||||||
|
}
|
||||||
token lexer::id_gen() {
|
return str;
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
std::string str = "";
|
token lexer::id_gen() {
|
||||||
while(ptr<res.size() && (is_id(res[ptr]) || is_dec(res[ptr]))) {
|
u32 begin_line = line;
|
||||||
if (res[ptr]<0) { // utf-8
|
u32 begin_column = column;
|
||||||
str += utf8_gen();
|
std::string str = "";
|
||||||
} else { // ascii
|
while(ptr<res.size() && (is_id(res[ptr]) || is_dec(res[ptr]))) {
|
||||||
str += res[ptr++];
|
if (res[ptr]<0) { // utf-8
|
||||||
++column;
|
str += utf8_gen();
|
||||||
}
|
} else { // ascii
|
||||||
}
|
str += res[ptr++];
|
||||||
tok type = get_type(str);
|
++column;
|
||||||
return {
|
}
|
||||||
{begin_line, begin_column, line, column, filename},
|
}
|
||||||
(type!=tok::null)? type:tok::id, str
|
tok type = get_type(str);
|
||||||
};
|
return {
|
||||||
}
|
{begin_line, begin_column, line, column, filename},
|
||||||
|
(type!=tok::null)? type:tok::id, str
|
||||||
token lexer::num_gen() {
|
};
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
// generate hex number
|
token lexer::num_gen() {
|
||||||
if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') {
|
u32 begin_line = line;
|
||||||
std::string str = "0x";
|
u32 begin_column = column;
|
||||||
ptr += 2;
|
// generate hex number
|
||||||
while(ptr<res.size() && is_hex(res[ptr])) {
|
if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x') {
|
||||||
str += res[ptr++];
|
std::string str = "0x";
|
||||||
}
|
ptr += 2;
|
||||||
column += str.length();
|
while(ptr<res.size() && is_hex(res[ptr])) {
|
||||||
// "0x"
|
str += res[ptr++];
|
||||||
if (str.length()<3) {
|
}
|
||||||
err.err("lexer",
|
column += str.length();
|
||||||
{begin_line, begin_column, line, column, filename},
|
// "0x"
|
||||||
"invalid number `"+str+"`"
|
if (str.length()<3) {
|
||||||
);
|
err.err("lexer",
|
||||||
}
|
{begin_line, begin_column, line, column, filename},
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
"invalid number `"+str+"`"
|
||||||
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
|
);
|
||||||
std::string str = "0o";
|
}
|
||||||
ptr += 2;
|
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||||
while(ptr<res.size() && is_oct(res[ptr])) {
|
} else if (ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o') { // generate oct number
|
||||||
str += res[ptr++];
|
std::string str = "0o";
|
||||||
}
|
ptr += 2;
|
||||||
bool erfmt = false;
|
while(ptr<res.size() && is_oct(res[ptr])) {
|
||||||
while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr]))) {
|
str += res[ptr++];
|
||||||
erfmt = true;
|
}
|
||||||
str += res[ptr++];
|
bool erfmt = false;
|
||||||
}
|
while(ptr<res.size() && (is_dec(res[ptr]) || is_hex(res[ptr]))) {
|
||||||
column += str.length();
|
erfmt = true;
|
||||||
if (str.length()==2 || erfmt) {
|
str += res[ptr++];
|
||||||
err.err("lexer",
|
}
|
||||||
{begin_line, begin_column, line, column, filename},
|
column += str.length();
|
||||||
"invalid number `"+str+"`"
|
if (str.length()==2 || erfmt) {
|
||||||
);
|
err.err("lexer",
|
||||||
}
|
{begin_line, begin_column, line, column, filename},
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
"invalid number `"+str+"`"
|
||||||
}
|
);
|
||||||
// generate dec number
|
}
|
||||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||||
std::string str = "";
|
}
|
||||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
// generate dec number
|
||||||
str += res[ptr++];
|
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||||
}
|
std::string str = "";
|
||||||
if (ptr<res.size() && res[ptr]=='.') {
|
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||||
str += res[ptr++];
|
str += res[ptr++];
|
||||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
}
|
||||||
str += res[ptr++];
|
if (ptr<res.size() && res[ptr]=='.') {
|
||||||
}
|
str += res[ptr++];
|
||||||
// "xxxx." is not a correct number
|
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||||
if (str.back()=='.') {
|
str += res[ptr++];
|
||||||
column += str.length();
|
}
|
||||||
err.err("lexer",
|
// "xxxx." is not a correct number
|
||||||
{begin_line, begin_column, line, column, filename},
|
if (str.back()=='.') {
|
||||||
"invalid number `"+str+"`"
|
column += str.length();
|
||||||
);
|
err.err("lexer",
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
{begin_line, begin_column, line, column, filename},
|
||||||
}
|
"invalid number `"+str+"`"
|
||||||
}
|
);
|
||||||
if (ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) {
|
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||||
str += res[ptr++];
|
}
|
||||||
if (ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+')) {
|
}
|
||||||
str += res[ptr++];
|
if (ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E')) {
|
||||||
}
|
str += res[ptr++];
|
||||||
while(ptr<res.size() && is_dec(res[ptr])) {
|
if (ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+')) {
|
||||||
str += res[ptr++];
|
str += res[ptr++];
|
||||||
}
|
}
|
||||||
// "xxxe(-|+)" is not a correct number
|
while(ptr<res.size() && is_dec(res[ptr])) {
|
||||||
if (str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+') {
|
str += res[ptr++];
|
||||||
column += str.length();
|
}
|
||||||
err.err("lexer",
|
// "xxxe(-|+)" is not a correct number
|
||||||
{begin_line, begin_column, line, column, filename},
|
if (str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+') {
|
||||||
"invalid number `"+str+"`"
|
column += str.length();
|
||||||
);
|
err.err("lexer",
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
{begin_line, begin_column, line, column, filename},
|
||||||
}
|
"invalid number `"+str+"`"
|
||||||
}
|
);
|
||||||
column += str.length();
|
return {{begin_line, begin_column, line, column, filename}, tok::num, "0"};
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
}
|
||||||
}
|
}
|
||||||
|
column += str.length();
|
||||||
token lexer::str_gen() {
|
return {{begin_line, begin_column, line, column, filename}, tok::num, str};
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
std::string str = "";
|
token lexer::str_gen() {
|
||||||
const char begin = res[ptr];
|
u32 begin_line = line;
|
||||||
++column;
|
u32 begin_column = column;
|
||||||
while(++ptr<res.size() && res[ptr]!=begin) {
|
std::string str = "";
|
||||||
++column;
|
const char begin = res[ptr];
|
||||||
if (res[ptr]=='\n') {
|
++column;
|
||||||
column = 0;
|
while(++ptr<res.size() && res[ptr]!=begin) {
|
||||||
++line;
|
++column;
|
||||||
}
|
if (res[ptr]=='\n') {
|
||||||
if (res[ptr]=='\\' && ptr+1<res.size()) {
|
column = 0;
|
||||||
++column;
|
++line;
|
||||||
++ptr;
|
}
|
||||||
switch(res[ptr]) {
|
if (res[ptr]=='\\' && ptr+1<res.size()) {
|
||||||
case '0': str += '\0'; break;
|
++column;
|
||||||
case 'a': str += '\a'; break;
|
++ptr;
|
||||||
case 'b': str += '\b'; break;
|
switch(res[ptr]) {
|
||||||
case 'e': str += '\033'; break;
|
case '0': str += '\0'; break;
|
||||||
case 't': str += '\t'; break;
|
case 'a': str += '\a'; break;
|
||||||
case 'n': str += '\n'; break;
|
case 'b': str += '\b'; break;
|
||||||
case 'v': str += '\v'; break;
|
case 'e': str += '\033'; break;
|
||||||
case 'f': str += '\f'; break;
|
case 't': str += '\t'; break;
|
||||||
case 'r': str += '\r'; break;
|
case 'n': str += '\n'; break;
|
||||||
case '?': str += '\?'; break;
|
case 'v': str += '\v'; break;
|
||||||
case '\\':str += '\\'; break;
|
case 'f': str += '\f'; break;
|
||||||
case '\'':str += '\''; break;
|
case 'r': str += '\r'; break;
|
||||||
case '\"':str += '\"'; break;
|
case '?': str += '\?'; break;
|
||||||
default: str += res[ptr];break;
|
case '\\':str += '\\'; break;
|
||||||
}
|
case '\'':str += '\''; break;
|
||||||
if (res[ptr]=='\n') {
|
case '\"':str += '\"'; break;
|
||||||
column = 0;
|
default: str += res[ptr];break;
|
||||||
++line;
|
}
|
||||||
}
|
if (res[ptr]=='\n') {
|
||||||
continue;
|
column = 0;
|
||||||
}
|
++line;
|
||||||
str += res[ptr];
|
}
|
||||||
}
|
continue;
|
||||||
// check if this string ends with a " or '
|
}
|
||||||
if (ptr++>=res.size()) {
|
str += res[ptr];
|
||||||
err.err("lexer",
|
}
|
||||||
{begin_line, begin_column, line, column, filename},
|
// check if this string ends with a " or '
|
||||||
"get EOF when generating string"
|
if (ptr++>=res.size()) {
|
||||||
);
|
err.err("lexer",
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
{begin_line, begin_column, line, column, filename},
|
||||||
}
|
"get EOF when generating string"
|
||||||
++column;
|
);
|
||||||
|
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||||
// if is not utf8, 1+utf8_hdchk should be 1
|
}
|
||||||
if (begin=='`' && str.length()!=1+utf8_hdchk(str[0])) {
|
++column;
|
||||||
err.err("lexer",
|
|
||||||
{begin_line, begin_column, line, column, filename},
|
// if is not utf8, 1+utf8_hdchk should be 1
|
||||||
"\'`\' is used for string including one character"
|
if (begin=='`' && str.length()!=1+utf8_hdchk(str[0])) {
|
||||||
);
|
err.err("lexer",
|
||||||
}
|
{begin_line, begin_column, line, column, filename},
|
||||||
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
"\'`\' is used for string including one character"
|
||||||
}
|
);
|
||||||
|
}
|
||||||
token lexer::single_opr() {
|
return {{begin_line, begin_column, line, column, filename}, tok::str, str};
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
std::string str(1, res[ptr]);
|
token lexer::single_opr() {
|
||||||
++column;
|
u32 begin_line = line;
|
||||||
tok type = get_type(str);
|
u32 begin_column = column;
|
||||||
if (type==tok::null) {
|
std::string str(1, res[ptr]);
|
||||||
err.err("lexer",
|
++column;
|
||||||
{begin_line, begin_column, line, column, filename},
|
tok type = get_type(str);
|
||||||
"invalid operator `"+str+"`"
|
if (type==tok::null) {
|
||||||
);
|
err.err("lexer",
|
||||||
}
|
{begin_line, begin_column, line, column, filename},
|
||||||
++ptr;
|
"invalid operator `"+str+"`"
|
||||||
return {{begin_line, begin_column, line, column, filename}, type, str};
|
);
|
||||||
}
|
}
|
||||||
|
++ptr;
|
||||||
token lexer::dots() {
|
return {{begin_line, begin_column, line, column, filename}, type, str};
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
std::string str = ".";
|
token lexer::dots() {
|
||||||
if (ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') {
|
u32 begin_line = line;
|
||||||
str += "..";
|
u32 begin_column = column;
|
||||||
}
|
std::string str = ".";
|
||||||
ptr += str.length();
|
if (ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.') {
|
||||||
column += str.length();
|
str += "..";
|
||||||
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
}
|
||||||
}
|
ptr += str.length();
|
||||||
|
column += str.length();
|
||||||
token lexer::calc_opr() {
|
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
||||||
u32 begin_line = line;
|
}
|
||||||
u32 begin_column = column;
|
|
||||||
// get calculation operator
|
token lexer::calc_opr() {
|
||||||
std::string str(1, res[ptr++]);
|
u32 begin_line = line;
|
||||||
if (ptr<res.size() && res[ptr]=='=') {
|
u32 begin_column = column;
|
||||||
str += res[ptr++];
|
// get calculation operator
|
||||||
}
|
std::string str(1, res[ptr++]);
|
||||||
column += str.length();
|
if (ptr<res.size() && res[ptr]=='=') {
|
||||||
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
str += res[ptr++];
|
||||||
}
|
}
|
||||||
|
column += str.length();
|
||||||
const error& lexer::scan(const std::string& file) {
|
return {{begin_line, begin_column, line, column, filename}, get_type(str), str};
|
||||||
line = 1;
|
}
|
||||||
column = 0;
|
|
||||||
ptr = 0;
|
const error& lexer::scan(const std::string& file) {
|
||||||
toks = {};
|
line = 1;
|
||||||
open(file);
|
column = 0;
|
||||||
|
ptr = 0;
|
||||||
while(ptr<res.size()) {
|
toks = {};
|
||||||
while(ptr<res.size() && skip(res[ptr])) {
|
open(file);
|
||||||
// these characters will be ignored, and '\n' will cause ++line
|
|
||||||
++column;
|
while(ptr<res.size()) {
|
||||||
if (res[ptr++]=='\n') {
|
while(ptr<res.size() && skip(res[ptr])) {
|
||||||
++line;
|
// these characters will be ignored, and '\n' will cause ++line
|
||||||
column = 0;
|
++column;
|
||||||
}
|
if (res[ptr++]=='\n') {
|
||||||
}
|
++line;
|
||||||
if (ptr>=res.size()) {
|
column = 0;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
if (is_id(res[ptr])) {
|
if (ptr>=res.size()) {
|
||||||
toks.push_back(id_gen());
|
break;
|
||||||
} else if (is_dec(res[ptr])) {
|
}
|
||||||
toks.push_back(num_gen());
|
if (is_id(res[ptr])) {
|
||||||
} else if (is_str(res[ptr])) {
|
toks.push_back(id_gen());
|
||||||
toks.push_back(str_gen());
|
} else if (is_dec(res[ptr])) {
|
||||||
} else if (is_single_opr(res[ptr])) {
|
toks.push_back(num_gen());
|
||||||
toks.push_back(single_opr());
|
} else if (is_str(res[ptr])) {
|
||||||
} else if (res[ptr]=='.') {
|
toks.push_back(str_gen());
|
||||||
toks.push_back(dots());
|
} else if (is_single_opr(res[ptr])) {
|
||||||
} else if (is_calc_opr(res[ptr])) {
|
toks.push_back(single_opr());
|
||||||
toks.push_back(calc_opr());
|
} else if (res[ptr]=='.') {
|
||||||
} else if (res[ptr]=='#') {
|
toks.push_back(dots());
|
||||||
skip_note();
|
} else if (is_calc_opr(res[ptr])) {
|
||||||
} else {
|
toks.push_back(calc_opr());
|
||||||
err_char();
|
} else if (res[ptr]=='#') {
|
||||||
}
|
skip_note();
|
||||||
if (invalid_char>10) {
|
} else {
|
||||||
err.err("lexer", "too many invalid characters, stop");
|
err_char();
|
||||||
break;
|
}
|
||||||
}
|
if (invalid_char>10) {
|
||||||
}
|
err.err("lexer", "too many invalid characters, stop");
|
||||||
if (toks.size()) {
|
break;
|
||||||
// eof token's location is the last token's location
|
}
|
||||||
toks.push_back({toks.back().loc, tok::eof, "<eof>"});
|
}
|
||||||
} else {
|
if (toks.size()) {
|
||||||
// if token sequence is empty, generate a default location
|
// eof token's location is the last token's location
|
||||||
toks.push_back({{line, column, line, column, filename}, tok::eof, "<eof>"});
|
toks.push_back({toks.back().loc, tok::eof, "<eof>"});
|
||||||
}
|
} else {
|
||||||
res = "";
|
// if token sequence is empty, generate a default location
|
||||||
return err;
|
toks.push_back({{line, column, line, column, filename}, tok::eof, "<eof>"});
|
||||||
}
|
}
|
||||||
|
res = "";
|
||||||
}
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
#include "nasal.h"
|
#include "nasal.h"
|
||||||
#include "nasal_err.h"
|
#include "nasal_err.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define S_ISREG(m) (((m)&0xF000)==0x8000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
enum class tok:u32 {
|
enum class tok:u32 {
|
||||||
|
|
Loading…
Reference in New Issue