#pragma once
|
|
|
|
#include "gp/containers/array.hpp"
|
|
#include "gp/containers/vector.hpp"
|
|
#include "gp/text/ascii.hpp"
|
|
|
|
using string = gp::vector<char>;
|
|
|
|
#define FOREACH_LEXEME_TYPE \
|
|
LEX(leftBracket) \
|
|
LEX(rightBracket) \
|
|
LEX(leftParenthesis) \
|
|
LEX(rightParenthesis) \
|
|
LEX(leftCurlyBrace) \
|
|
LEX(rightCurlyBrace) \
|
|
LEX(period) \
|
|
LEX(semicolon) \
|
|
LEX(colon) \
|
|
LEX(doubleColon) \
|
|
LEX(comma) \
|
|
LEX(at) \
|
|
LEX(pointer) \
|
|
LEX(as) \
|
|
LEX(try_) \
|
|
LEX(catch_) \
|
|
LEX(raise_) \
|
|
LEX(defer) \
|
|
LEX(assign) \
|
|
LEX(addAssign) \
|
|
LEX(substractAssign) \
|
|
LEX(multiplyAssign) \
|
|
LEX(divideAssign) \
|
|
LEX(concatenateAssign) \
|
|
LEX(remainderAssign) \
|
|
LEX(powerAssign) \
|
|
LEX(plus) \
|
|
LEX(minus) \
|
|
LEX(add) \
|
|
LEX(substract) \
|
|
LEX(multiply) \
|
|
LEX(divide) \
|
|
LEX(concatenate) \
|
|
LEX(remainder) \
|
|
LEX(power) \
|
|
LEX(equal) \
|
|
LEX(doubleEqual) \
|
|
LEX(threeWayComparison) \
|
|
LEX(notEqual) \
|
|
LEX(greaterOrEqual) \
|
|
LEX(greater) \
|
|
LEX(lesserOrEqual) \
|
|
LEX(lesser) \
|
|
LEX(leftShift) \
|
|
LEX(rightShift) \
|
|
LEX(and_) \
|
|
LEX(or_) \
|
|
LEX(xor_) \
|
|
LEX(not_) \
|
|
LEX(increment) \
|
|
LEX(decrement) \
|
|
LEX(identifier) \
|
|
LEX(integer) \
|
|
LEX(float_) \
|
|
LEX(boolean) \
|
|
LEX(string_) \
|
|
LEX(null_) \
|
|
LEX(public_) \
|
|
LEX(main_) \
|
|
LEX(type_) \
|
|
LEX(event_) \
|
|
LEX(class_) \
|
|
LEX(enum_) \
|
|
LEX(template_) \
|
|
LEX(new_) \
|
|
LEX(copy) \
|
|
LEX(send) \
|
|
LEX(receive) \
|
|
LEX(intType) \
|
|
LEX(floatType) \
|
|
LEX(boolType) \
|
|
LEX(stringType) \
|
|
LEX(arrayType) \
|
|
LEX(functionType) \
|
|
LEX(taskType) \
|
|
LEX(chanType) \
|
|
LEX(autoType) \
|
|
LEX(if_) \
|
|
LEX(unless) \
|
|
LEX(else_) \
|
|
LEX(switch_) \
|
|
LEX(select) \
|
|
LEX(case_) \
|
|
LEX(while_) \
|
|
LEX(do_) \
|
|
LEX(until) \
|
|
LEX(for_) \
|
|
LEX(loop) \
|
|
LEX(return_) \
|
|
LEX(self) \
|
|
LEX(kill) \
|
|
LEX(killAll) \
|
|
LEX(yield) \
|
|
LEX(break_) \
|
|
LEX(continue_)
|
|
|
|
#define LEX(x) x,
|
|
enum class gr_lexeme_type {
|
|
FOREACH_LEXEME_TYPE
|
|
};
|
|
#undef LEX
|
|
|
|
#define LEX(x) case gr_lexeme_type::x: return #x;
|
|
constexpr inline const char* to_string(const gr_lexeme_type& value) {
|
|
switch(value) {
|
|
FOREACH_LEXEME_TYPE
|
|
}
|
|
}
|
|
#undef LEX
|
|
|
|
#define LEX(x) +1
|
|
constexpr inline const char* to_pretty_string(const gr_lexeme_type& value) {
|
|
constexpr gp::array<const char*, 0 + FOREACH_LEXEME_TYPE> names = {
|
|
"[", "]", "(", ")", "{", "}", ".", ";", ":", "::", ",", "@", "&", "as",
|
|
"try", "catch", "raise", "defer", "=", "+=", "-=", "*=", "/=", "~=",
|
|
"%=", "^=", "+", "-", "+", "-", "*", "/", "~", "%", "^", "==", "===",
|
|
"<=>", "!=", ">=", ">", "<=", "<", "<<", ">>", "and", "or", "xor", "not", "++",
|
|
"--", "identifier", "const_int", "const_float", "const_bool",
|
|
"const_str", "null", "pub", "main", "type", "event", "class", "enum",
|
|
"template", "new", "copy", "send", "receive", "int", "float", "bool",
|
|
"string", "array", "func", "task", "chan", "let", "if", "unless",
|
|
"else", "switch", "select", "case", "while", "do", "until", "for", "loop",
|
|
"return", "self", "kill", "killall", "yield", "break", "continue"
|
|
};
|
|
return names[(size_t)value];
|
|
}
|
|
#undef LEX
|
|
|
|
struct gr_lexeme;
|
|
|
|
class gr_lexer {
|
|
public:
|
|
using file_loader_t = gp::function<gp::vector<char>(const gp::vector<char>&)>;
|
|
gp::allocator& _allocator;
|
|
file_loader_t file_loader;
|
|
private:
|
|
gp::vector<string> _files_to_import, _files_imported, _lines;
|
|
|
|
string _file, _text;
|
|
uint64_t _line, _current, _position_of_line, _file_id;
|
|
|
|
gp::vector<gr_lexeme> _lexemes;
|
|
|
|
char get(ssize_t offset = 0);
|
|
bool advance(bool start_from_current = false);
|
|
void scan_script();
|
|
void scan_number();
|
|
void scan_string();
|
|
void scan_operator();
|
|
void scan_word();
|
|
void scan_file_path();
|
|
void scan_use();
|
|
string convert_path_to_import(string&);
|
|
|
|
public:
|
|
|
|
gr_lexer(gp::allocator& alloc, file_loader_t& loader)
|
|
: _allocator(alloc)
|
|
, file_loader(loader)
|
|
, _files_to_import(_allocator)
|
|
, _files_imported(_allocator)
|
|
, _lines(_allocator)
|
|
, _file(_allocator)
|
|
, _text(_allocator)
|
|
, _lexemes(_allocator)
|
|
{}
|
|
|
|
const gp::vector<gr_lexeme>& lexemes() {
|
|
return _lexemes;
|
|
}
|
|
|
|
void scan_file(gp::vector<char>& file_name);
|
|
|
|
const string& get_line(const gr_lexeme&) const;
|
|
const string& get_file(const gr_lexeme&) const;
|
|
const string& get_file(const size_t&) const;
|
|
};
|
|
|
|
struct gr_lexeme {
|
|
const gr_lexer& lexer;
|
|
size_t _file_id;
|
|
size_t _line, _column, _text_length = 1;
|
|
|
|
gr_lexeme_type type;
|
|
bool
|
|
is_literal,
|
|
is_operator,
|
|
is_keyword,
|
|
is_type;
|
|
int ivalue;
|
|
float fvalue;
|
|
bool bvalue;
|
|
string svalue;
|
|
|
|
gr_lexeme(const gr_lexer& v)
|
|
: lexer(v)
|
|
, svalue(v._allocator)
|
|
{}
|
|
|
|
const string& get_line() const {
|
|
return lexer.get_line(*this);
|
|
}
|
|
|
|
const string& get_file() {
|
|
return lexer.get_file(*this);
|
|
}
|
|
};
|
|
|
|
inline char gr_lexer::get(ssize_t offset) {
|
|
const uint position = ssize_t(_current) + offset;
|
|
gp_config::assertion(!(position < 0 || position >= _text.size()), "Unexpected end of script");
|
|
return _text[position];
|
|
}
|
|
|
|
inline const string& gr_lexer::get_line(const gr_lexeme& lex) const {
|
|
gp_config::assertion(!(lex._file_id >= _files_imported.size()), "Lexeme file id out of bounds");
|
|
// TODO: Implement this
|
|
return _files_imported[lex._file_id];
|
|
}
|
|
|
|
inline const string& gr_lexer::get_file(const gr_lexeme& lex) const {
|
|
gp_config::assertion(!(lex._file_id >= _files_imported.size()), "Lexeme file id out of bounds");
|
|
return _files_imported[lex._file_id];
|
|
}
|
|
|
|
inline const string& gr_lexer::get_file(const size_t& file_id) const {
|
|
gp_config::assertion(!(file_id >= _files_imported.size()), "File id out of bounds");
|
|
return _files_imported[file_id];
|
|
}
|
|
|
|
inline bool gr_lexer::advance(bool start_from_current) {
|
|
if(!start_from_current) {
|
|
_current++;
|
|
}
|
|
|
|
if(_current >= _text.size()) {
|
|
return false;
|
|
}
|
|
|
|
char symbol = _text[_current];
|
|
|
|
whileLoop: while(symbol <= 0x20 || symbol == '/' || symbol == '#') {
|
|
if(_current >= _text.size()) {
|
|
return false;
|
|
}
|
|
|
|
symbol = _text[_current];
|
|
|
|
if(symbol == '\n') {
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}
|
|
else if(symbol == '#')
|
|
{
|
|
do {
|
|
if(_current >= _text.size()) return false;
|
|
_current++;
|
|
} while (_text[_current] != '\n');
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}
|
|
else if(symbol == '/')
|
|
{
|
|
if((_current + 1) >= _text.size()) {
|
|
return false;
|
|
}
|
|
|
|
switch(_text[_current + 1]) {
|
|
case '/': {
|
|
do {
|
|
if(_current >= _text.size()) {
|
|
return false;
|
|
}
|
|
} while(_current < _text.size() && _text[_current] != '\n');
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}break;
|
|
case '*': {
|
|
for(;;) {
|
|
if((_current + 1) >= _text.size()) {
|
|
_current++;
|
|
return false;
|
|
}
|
|
|
|
if(_text[_current] == '\n') {
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}
|
|
|
|
if(_text[_current] == '*' && _text[_current + 1] == '/') {
|
|
_current++;
|
|
break;
|
|
}
|
|
|
|
_current++;
|
|
}
|
|
}break;
|
|
default:
|
|
// Goto honorable
|
|
goto whileLoop;
|
|
}
|
|
}
|
|
|
|
_current++;
|
|
|
|
if(_current >= _text.size()) {
|
|
return false;
|
|
}
|
|
|
|
symbol = _text[_current];
|
|
}
|
|
return true;
|
|
}
|
|
|
|
inline void gr_lexer::scan_script() {
|
|
advance(true);
|
|
|
|
constexpr static auto is_operator = [](char v) {
|
|
if(v == '!') return true;
|
|
if(v >= '#' && v <='&') return true;
|
|
if(v >= '(' && v <='-') return true;
|
|
if(v == '/') return true;
|
|
if(v >= ':' && v <='@') return true;
|
|
if(v >= '[' && v <='^') return true;
|
|
if(v >= '{' && v <='~') return true;
|
|
return false;
|
|
};
|
|
|
|
do {
|
|
if (_current >= _text.size())
|
|
break;
|
|
auto c = get();
|
|
if(is_digit(c)) scan_number();
|
|
else if(c == '.') {
|
|
if (get(1) >= '0' && get(1) <= '9')
|
|
scan_number();
|
|
else
|
|
scan_operator();
|
|
}
|
|
else if(is_operator(c)) scan_operator();
|
|
else if(c == '\"') scan_string();
|
|
else scan_word();
|
|
}while (advance());
|
|
}
|
|
|
|
inline void gr_lexer::scan_number(){
|
|
gr_lexeme lex = gr_lexeme(*this);
|
|
lex.is_literal = true;
|
|
|
|
bool isFloat;
|
|
string buffer(_allocator);
|
|
for (;;) {
|
|
char symbol = get();
|
|
|
|
if (symbol >= '0' && symbol <= '9')
|
|
buffer.push_back(symbol);
|
|
else if (symbol == '_') {
|
|
// Do nothing, only cosmetic (e.g. 1_000_000).
|
|
}
|
|
else if (symbol == '.') {
|
|
if (isFloat)
|
|
break;
|
|
isFloat = true;
|
|
buffer.push_back(symbol);
|
|
}
|
|
else if (symbol == 'f') {
|
|
isFloat = true;
|
|
break;
|
|
}
|
|
else {
|
|
if (_current)
|
|
_current--;
|
|
break;
|
|
}
|
|
|
|
_current++;
|
|
|
|
if (_current >= _text.size())
|
|
break;
|
|
}
|
|
}
|
|
|
|
inline void gr_lexer::scan_string(){
|
|
gr_lexeme lex = gr_lexeme(*this);
|
|
lex.type = gr_lexeme_type::string_;
|
|
lex.is_literal = true;
|
|
|
|
gp_config::assertion(get() != '\"',"Expected \'\"\' at the beginning of the string.");
|
|
_current++;
|
|
|
|
string buffer(_allocator);
|
|
bool escape = false;
|
|
bool wasEscape = false;
|
|
for (;;) {
|
|
gp_config::assertion(_current >= _text.size(),"Missing \'\"\' character.");
|
|
char symbol = get();
|
|
|
|
if (symbol == '\n') {
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}
|
|
else if (symbol == '\"' && (!wasEscape))
|
|
break;
|
|
else if (symbol == '\\' && (!wasEscape)) {
|
|
escape = true;
|
|
}
|
|
|
|
if (!escape) {
|
|
if (!wasEscape) {
|
|
buffer.push_back(symbol);
|
|
}
|
|
else {
|
|
if (symbol == 'n')
|
|
buffer.push_back('\n');
|
|
else
|
|
buffer.push_back(symbol);
|
|
}
|
|
}
|
|
wasEscape = escape;
|
|
escape = false;
|
|
|
|
_current++;
|
|
}
|
|
|
|
lex._text_length = size_t(buffer.size() + 2u);
|
|
lex.svalue = buffer;
|
|
_lexemes.push_back(lex);
|
|
}
|
|
|
|
inline void gr_lexer::scan_operator(){
|
|
gr_lexeme lex = gr_lexeme(*this);
|
|
lex.is_operator = true;
|
|
|
|
switch (get()) {
|
|
case '{':
|
|
lex.type = gr_lexeme_type::leftCurlyBrace;
|
|
break;
|
|
case '}':
|
|
lex.type = gr_lexeme_type::rightCurlyBrace;
|
|
break;
|
|
case '(':
|
|
lex.type = gr_lexeme_type::leftParenthesis;
|
|
break;
|
|
case ')':
|
|
lex.type = gr_lexeme_type::rightParenthesis;
|
|
break;
|
|
case '[':
|
|
lex.type = gr_lexeme_type::leftBracket;
|
|
break;
|
|
case ']':
|
|
lex.type = gr_lexeme_type::rightBracket;
|
|
break;
|
|
case '.':
|
|
lex.type = gr_lexeme_type::period;
|
|
break;
|
|
case ';':
|
|
lex.type = gr_lexeme_type::semicolon;
|
|
break;
|
|
case ':':
|
|
lex.type = gr_lexeme_type::colon;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == ':') {
|
|
lex.type = gr_lexeme_type::doubleColon;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case ',':
|
|
lex.type = gr_lexeme_type::comma;
|
|
break;
|
|
case '^':
|
|
lex.type = gr_lexeme_type::power;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::powerAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '@':
|
|
lex.type = gr_lexeme_type::at;
|
|
break;
|
|
case '&':
|
|
lex.type = gr_lexeme_type::pointer;
|
|
break;
|
|
case '~':
|
|
lex.type = gr_lexeme_type::concatenate;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::concatenateAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '+':
|
|
lex.type = gr_lexeme_type::add;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
switch (get(1)) {
|
|
case '=':
|
|
lex.type = gr_lexeme_type::addAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
break;
|
|
case '+':
|
|
lex.type = gr_lexeme_type::increment;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case '-':
|
|
lex.type = gr_lexeme_type::substract;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
switch (get(1)) {
|
|
case '=':
|
|
lex.type = gr_lexeme_type::substractAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
break;
|
|
case '-':
|
|
lex.type = gr_lexeme_type::decrement;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case '*':
|
|
lex.type = gr_lexeme_type::multiply;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::multiplyAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '/':
|
|
lex.type = gr_lexeme_type::divide;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::divideAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '%':
|
|
lex.type = gr_lexeme_type::remainder;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::remainderAssign;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '=':
|
|
lex.type = gr_lexeme_type::assign;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::equal;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::doubleEqual;
|
|
lex._text_length = 3;
|
|
_current++;
|
|
}
|
|
}
|
|
break;
|
|
case '<':
|
|
lex.type = gr_lexeme_type::lesser;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::lesserOrEqual;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '>') {
|
|
lex.type = gr_lexeme_type::threeWayComparison;
|
|
lex._text_length = 3;
|
|
_current++;
|
|
}
|
|
}
|
|
else if (get(1) == '-') {
|
|
lex.type = gr_lexeme_type::send;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
else if (get(1) == '<') {
|
|
lex.type = gr_lexeme_type::leftShift;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '>':
|
|
lex.type = gr_lexeme_type::greater;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::greaterOrEqual;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
else if (get(1) == '>') {
|
|
lex.type = gr_lexeme_type::rightShift;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
case '!':
|
|
lex.type = gr_lexeme_type::not_;
|
|
if (_current + 1 >= _text.size())
|
|
break;
|
|
if (get(1) == '=') {
|
|
lex.type = gr_lexeme_type::notEqual;
|
|
lex._text_length = 2;
|
|
_current++;
|
|
}
|
|
break;
|
|
default:
|
|
gp_config::assertion(false, "GrLexer: invalid operator");
|
|
}
|
|
|
|
_lexemes.push_back(lex);
|
|
}
|
|
|
|
namespace _hidden {
|
|
bool operator==(const gp::vector<char>& lhs, const char* rhs) {
|
|
for(size_t index = 0; index < lhs.size() && rhs[index] != 0; index++){
|
|
if(lhs[index] != rhs[index]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
inline void gr_lexer::scan_word(){
|
|
gr_lexeme lex = gr_lexeme(*this);
|
|
lex.is_keyword = true;
|
|
|
|
string symbol_buffer(_allocator);
|
|
for (;;) {
|
|
if (_current >= _text.size())
|
|
break;
|
|
|
|
char symbol = get();
|
|
if (symbol == '!' || symbol == '?') {
|
|
symbol_buffer.push_back(symbol);
|
|
_current++;
|
|
break;
|
|
}
|
|
if (symbol <= '&' || (symbol >= '(' && symbol <= '/') || (symbol >= ':'
|
|
&& symbol <= '@') || (symbol >= '[' && symbol <= '^')
|
|
|| (symbol >= '{' && symbol <= 0x7F))
|
|
break;
|
|
|
|
symbol_buffer.push_back(symbol);
|
|
_current++;
|
|
}
|
|
_current--;
|
|
|
|
lex._text_length = symbol_buffer.size();
|
|
|
|
using namespace _hidden;
|
|
|
|
if(symbol_buffer == "use"){
|
|
scan_use();
|
|
return;
|
|
}
|
|
else if(symbol_buffer == "pub"){
|
|
lex.type = gr_lexeme_type::public_;
|
|
}
|
|
else if(symbol_buffer == "main"){
|
|
lex.type = gr_lexeme_type::main_;
|
|
}
|
|
else if(symbol_buffer == "type"){
|
|
lex.type = gr_lexeme_type::type_;
|
|
}
|
|
else if(symbol_buffer == "event"){
|
|
lex.type = gr_lexeme_type::event_;
|
|
}
|
|
else if(symbol_buffer == "class"){
|
|
lex.type = gr_lexeme_type::class_;
|
|
}
|
|
else if(symbol_buffer == "enum"){
|
|
lex.type = gr_lexeme_type::enum_;
|
|
}
|
|
else if(symbol_buffer == "template"){
|
|
lex.type = gr_lexeme_type::template_;
|
|
}
|
|
else if(symbol_buffer == "if"){
|
|
lex.type = gr_lexeme_type::if_;
|
|
}
|
|
else if(symbol_buffer == "unless"){
|
|
lex.type = gr_lexeme_type::unless;
|
|
}
|
|
else if(symbol_buffer == "else"){
|
|
lex.type = gr_lexeme_type::else_;
|
|
}
|
|
else if(symbol_buffer == "switch"){
|
|
lex.type = gr_lexeme_type::switch_;
|
|
}
|
|
else if(symbol_buffer == "select"){
|
|
lex.type = gr_lexeme_type::select;
|
|
}
|
|
else if(symbol_buffer == "case"){
|
|
lex.type = gr_lexeme_type::case_;
|
|
}
|
|
else if(symbol_buffer == "while"){
|
|
lex.type = gr_lexeme_type::while_;
|
|
}
|
|
else if(symbol_buffer == "do"){
|
|
lex.type = gr_lexeme_type::do_;
|
|
}
|
|
else if(symbol_buffer == "until"){
|
|
lex.type = gr_lexeme_type::until;
|
|
}
|
|
else if(symbol_buffer == "for"){
|
|
lex.type = gr_lexeme_type::for_;
|
|
}
|
|
else if(symbol_buffer == "loop"){
|
|
lex.type = gr_lexeme_type::loop;
|
|
}
|
|
else if(symbol_buffer == "return"){
|
|
lex.type = gr_lexeme_type::return_;
|
|
}
|
|
else if(symbol_buffer == "self"){
|
|
lex.type = gr_lexeme_type::self;
|
|
}
|
|
else if(symbol_buffer == "kill"){
|
|
lex.type = gr_lexeme_type::kill;
|
|
}
|
|
else if(symbol_buffer == "killall"){
|
|
lex.type = gr_lexeme_type::killAll;
|
|
}
|
|
else if(symbol_buffer == "yield"){
|
|
lex.type = gr_lexeme_type::yield;
|
|
}
|
|
else if(symbol_buffer == "break"){
|
|
lex.type = gr_lexeme_type::break_;
|
|
}
|
|
else if(symbol_buffer == "continue"){
|
|
lex.type = gr_lexeme_type::continue_;
|
|
}
|
|
else if(symbol_buffer == "as"){
|
|
lex.type = gr_lexeme_type::as;
|
|
}
|
|
else if(symbol_buffer == "try"){
|
|
lex.type = gr_lexeme_type::try_;
|
|
}
|
|
else if(symbol_buffer == "catch"){
|
|
lex.type = gr_lexeme_type::catch_;
|
|
}
|
|
else if(symbol_buffer == "raise"){
|
|
lex.type = gr_lexeme_type::raise_;
|
|
}
|
|
else if(symbol_buffer == "defer"){
|
|
lex.type = gr_lexeme_type::defer;
|
|
}
|
|
else if(symbol_buffer == "task"){
|
|
lex.type = gr_lexeme_type::taskType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "func"){
|
|
lex.type = gr_lexeme_type::functionType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "int"){
|
|
lex.type = gr_lexeme_type::intType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "float"){
|
|
lex.type = gr_lexeme_type::floatType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "bool"){
|
|
lex.type = gr_lexeme_type::boolType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "string"){
|
|
lex.type = gr_lexeme_type::stringType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "array"){
|
|
lex.type = gr_lexeme_type::arrayType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "chan"){
|
|
lex.type = gr_lexeme_type::chanType;
|
|
lex.is_type = true;
|
|
}
|
|
else if(symbol_buffer == "new"){
|
|
lex.type = gr_lexeme_type::new_;
|
|
lex.is_type = false;
|
|
}
|
|
else if(symbol_buffer == "let"){
|
|
lex.type = gr_lexeme_type::autoType;
|
|
lex.is_type = false;
|
|
}
|
|
else if(symbol_buffer == "true"){
|
|
lex.type = gr_lexeme_type::boolean;
|
|
lex.is_keyword = false;
|
|
lex.is_literal = true;
|
|
lex.bvalue = true;
|
|
}
|
|
else if(symbol_buffer == "false"){
|
|
lex.type = gr_lexeme_type::boolean;
|
|
lex.is_keyword = false;
|
|
lex.is_literal = true;
|
|
lex.bvalue = false;
|
|
}
|
|
else if(symbol_buffer == "null"){
|
|
lex.type = gr_lexeme_type::null_;
|
|
lex.is_keyword = false;
|
|
lex.is_literal = true;
|
|
}
|
|
else if(symbol_buffer == "not"){
|
|
lex.type = gr_lexeme_type::not_;
|
|
lex.is_keyword = false;
|
|
lex.is_operator = true;
|
|
}
|
|
else if(symbol_buffer == "and"){
|
|
lex.type = gr_lexeme_type::and_;
|
|
lex.is_keyword = false;
|
|
lex.is_operator = true;
|
|
}
|
|
else if(symbol_buffer == "or"){
|
|
lex.type = gr_lexeme_type::or_;
|
|
lex.is_keyword = false;
|
|
lex.is_operator = true;
|
|
}
|
|
else if(symbol_buffer == "xor"){
|
|
lex.type = gr_lexeme_type::xor_;
|
|
lex.is_keyword = false;
|
|
lex.is_operator = true;
|
|
} else {
|
|
lex.is_keyword = false;
|
|
lex.type = gr_lexeme_type::identifier;
|
|
lex.svalue = symbol_buffer;
|
|
}
|
|
|
|
_lexemes.push_back(lex);
|
|
}
|
|
|
|
inline string gr_lexer::convert_path_to_import(string& path) {
|
|
return path;
|
|
}
|
|
|
|
inline void gr_lexer::scan_file(gp::vector<char>& file_name){
|
|
_files_to_import.push_back(file_name);
|
|
|
|
while (_files_to_import.size()) {
|
|
_file = _files_to_import[_files_to_import.size()-1];
|
|
_files_imported.push_back(_file);
|
|
_text = file_loader(file_name);
|
|
_files_to_import.pop_back();
|
|
|
|
_line = 0u;
|
|
_current = 0u;
|
|
_lines = gp::vector<string>(_allocator);
|
|
|
|
gp::vector<char> tmp(_allocator);
|
|
for(char c : _text) {
|
|
if(c == '\n') {
|
|
_lines.push_back(tmp);
|
|
tmp = gp::vector<char>(_allocator);
|
|
} else {
|
|
tmp.push_back(c);
|
|
}
|
|
}
|
|
|
|
scan_script();
|
|
|
|
_file_id++;
|
|
}
|
|
}
|
|
|
|
inline void gr_lexer::scan_file_path(){
|
|
gp_config::assertion(get() != '\"', "Expected \'\"\' at the beginning of the import.");
|
|
_current++;
|
|
|
|
string buffer(_allocator);
|
|
for (;;) {
|
|
gp_config::assertion(_current >= _text.size(), "Missing \'\"\' character.");
|
|
char symbol = get();
|
|
if (symbol == '\n') {
|
|
_position_of_line = _current;
|
|
_line++;
|
|
}
|
|
else if (symbol == '\"')
|
|
break;
|
|
|
|
buffer.push_back(symbol);
|
|
_current++;
|
|
}
|
|
buffer = convert_path_to_import(buffer);
|
|
|
|
for(auto& file : _files_imported) {
|
|
if(file == buffer) return;
|
|
}
|
|
for(auto& file : _files_to_import) {
|
|
if(file == buffer) return;
|
|
}
|
|
|
|
_files_to_import.push_back(buffer);
|
|
}
|
|
|
|
inline void gr_lexer::scan_use(){
|
|
advance();
|
|
|
|
// Multiple files import.
|
|
if (get() == '{') {
|
|
advance();
|
|
bool isFirst = true;
|
|
for (;;) {
|
|
if (isFirst)
|
|
isFirst = false;
|
|
else if (get() == '\"')
|
|
advance();
|
|
else
|
|
gp_config::assertion(false, "Missing \'}\' after import list.");
|
|
// EOF
|
|
gp_config::assertion(_current >= _text.size(), "Missing \'}\' after import list.");
|
|
// End of the import list.
|
|
if (get() == '}')
|
|
break;
|
|
// Scan
|
|
scan_file_path();
|
|
}
|
|
}
|
|
else {
|
|
scan_file_path();
|
|
}
|
|
}
|