1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +00:00

Add triple quotes asms (#463)

* Add python-like triple quotes for multiline strings

* Add test for multiline asm

* Allow asm definition duplicate

* Asm duplicate: add test & fixes

* Fix multiline asm

* Fix asm duplicate

Co-authored-by: legaii <jgates.ardux@gmail.com>
This commit is contained in:
EmelyanenkoK 2022-09-22 16:54:26 +03:00 committed by GitHub
parent e913871f4f
commit d23267d996
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 13 deletions

View file

@ -1631,6 +1631,7 @@ inline compile_func_t make_ext_compile(AsmOp op) {
struct SymValAsmFunc : SymValFunc {
simple_compile_func_t simple_compile;
compile_func_t ext_compile;
td::uint64 crc;
~SymValAsmFunc() override = default;
SymValAsmFunc(TypeExpr* ft, const AsmOp& _macro, bool impure = false)
: SymValFunc(-1, ft, impure), simple_compile(make_simple_compile(_macro)) {

View file

@ -1270,19 +1270,48 @@ SymValAsmFunc* parse_asm_func_body(Lexer& lex, TypeExpr* func_type, const Formal
lex.expect(')');
}
while (lex.tp() == _String) {
asm_ops.push_back(AsmOp::Parse(lex.cur().str, cnt, width));
lex.next();
if (asm_ops.back().is_custom()) {
cnt = width;
std::string ops = lex.cur().str; // <op>\n<op>\n...
std::string op;
for (const char& c : ops) {
if (c == '\n') {
if (!op.empty()) {
asm_ops.push_back(AsmOp::Parse(op, cnt, width));
if (asm_ops.back().is_custom()) {
cnt = width;
}
op.clear();
}
} else {
op.push_back(c);
}
}
if (!op.empty()) {
asm_ops.push_back(AsmOp::Parse(op, cnt, width));
if (asm_ops.back().is_custom()) {
cnt = width;
}
}
lex.next();
}
if (asm_ops.empty()) {
throw src::ParseError{lex.cur().loc, "string with assembler instruction expected"};
}
lex.expect(';');
std::string crc_s;
for (const AsmOp& asm_op : asm_ops) {
crc_s += asm_op.op;
}
crc_s.push_back(impure);
for (const int& x : arg_order) {
crc_s += std::string((const char*) (&x), (const char*) (&x + 1));
}
for (const int& x : ret_order) {
crc_s += std::string((const char*) (&x), (const char*) (&x + 1));
}
auto res = new SymValAsmFunc{func_type, asm_ops, impure};
res->arg_order = std::move(arg_order);
res->ret_order = std::move(ret_order);
res->crc = td::crc64(crc_s);
return res;
}
@ -1448,16 +1477,22 @@ void parse_func_def(Lexer& lex) {
// code->print(std::cerr); // !!!DEBUG!!!
func_sym_code->code = code;
} else {
Lexem asm_lexem = lex.cur();
SymValAsmFunc* asm_func = parse_asm_func_body(lex, func_type, arg_list, ret_type, impure);
if (func_sym_val) {
if (dynamic_cast<SymValCodeFunc*>(func_sym_val)) {
lex.cur().error("function `"s + func_name.str + "` was already declared as an ordinary function");
asm_lexem.error("function `"s + func_name.str + "` was already declared as an ordinary function");
}
if (dynamic_cast<SymValAsmFunc*>(func_sym_val)) {
lex.cur().error("redefinition of built-in assembler function `"s + func_name.str + "`");
SymValAsmFunc* asm_func_old = dynamic_cast<SymValAsmFunc*>(func_sym_val);
if (asm_func_old) {
if (asm_func->crc != asm_func_old->crc) {
asm_lexem.error("redefinition of built-in assembler function `"s + func_name.str + "`");
}
} else {
asm_lexem.error("redefinition of previously (somehow) defined function `"s + func_name.str + "`");
}
lex.cur().error("redefinition of previously (somehow) defined function `"s + func_name.str + "`");
}
func_sym->value = parse_asm_func_body(lex, func_type, arg_list, ret_type, impure);
func_sym->value = asm_func;
}
if (method_id.not_null()) {
auto val = dynamic_cast<SymVal*>(func_sym->value);

26
crypto/func/test/s2.fc Normal file
View file

@ -0,0 +1,26 @@
slice test1() asm """
"Test" $>s
PUSHSLICE
""";
slice test2() asm """
"Hello"
" "
"World"
$+ $+ $>s
PUSHSLICE
""";
int sdeq (slice s1, slice s2) asm """SDEQ""";
int sdeq (slice s1, slice s2) asm "SDEQ" "";
int sdeq (slice s1, slice s2) asm "" """
SDEQ
""";
() main() {
slice s = test1();
throw_unless(101, sdeq(s, "Test"));
slice s = test2();
throw_unless(102, sdeq(s, "Hello World"));
}

View file

@ -125,8 +125,9 @@ int Lexem::set(std::string _str, const SrcLocation& _loc, int _tp, int _val) {
}
Lexer::Lexer(SourceReader& _src, bool init, std::string active_chars, std::string eol_cmts, std::string open_cmts,
std::string close_cmts, std::string quote_chars)
: src(_src), eof(false), lexem("", src.here(), Lexem::Undefined), peek_lexem("", {}, Lexem::Undefined) {
std::string close_cmts, std::string quote_chars, std::string multiline_quote)
: src(_src), eof(false), lexem("", src.here(), Lexem::Undefined), peek_lexem("", {}, Lexem::Undefined),
multiline_quote(std::move(multiline_quote)) {
std::memset(char_class, 0, sizeof(char_class));
unsigned char activity = cc::active;
for (char c : active_chars) {
@ -171,6 +172,19 @@ void Lexer::set_spec(std::array<int, 3>& arr, std::string setup) {
}
}
bool Lexer::is_multiline_quote(const char* begin, const char* end) {
if (multiline_quote.empty()) {
return false;
}
for (const char& c : multiline_quote) {
if (begin == end || *begin != c) {
return false;
}
++begin;
}
return true;
}
void Lexer::expect(int exp_tp, const char* msg) {
if (tp() != exp_tp) {
throw ParseError{lexem.loc, (msg ? std::string{msg} : Lexem::lexem_name_str(exp_tp)) + " expected instead of " +
@ -234,6 +248,37 @@ const Lexem& Lexer::next() {
}
return lexem.clear(src.here(), Lexem::Eof);
}
if (is_multiline_quote(src.get_ptr(), src.get_end_ptr())) {
src.advance(multiline_quote.size());
const char* begin = src.get_ptr();
const char* end = nullptr;
SrcLocation here = src.here();
std::string body;
while (!src.is_eof()) {
if (src.is_eoln()) {
body.push_back('\n');
src.load_line();
continue;
}
if (is_multiline_quote(src.get_ptr(), src.get_end_ptr())) {
end = src.get_ptr();
src.advance(multiline_quote.size());
break;
}
body.push_back(src.cur_char());
src.advance(1);
}
if (!end) {
src.error("string extends past end of file");
}
lexem.set(body, here, Lexem::String);
int c = src.cur_char();
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
lexem.val = c;
src.advance(1);
}
return lexem;
}
int c = src.cur_char();
const char* end = src.get_ptr();
if (is_quote_char(c) || c == '`') {

View file

@ -71,6 +71,7 @@ class Lexer {
Lexem lexem, peek_lexem;
unsigned char char_class[128];
std::array<int, 3> eol_cmt, cmt_op, cmt_cl;
std::string multiline_quote;
enum cc { left_active = 2, right_active = 1, active = 3, allow_repeat = 4, quote_char = 8 };
public:
@ -78,7 +79,8 @@ class Lexer {
return eof;
}
Lexer(SourceReader& _src, bool init = false, std::string active_chars = ";,() ~.", std::string eol_cmts = ";;",
std::string open_cmts = "{-", std::string close_cmts = "-}", std::string quote_chars = "\"");
std::string open_cmts = "{-", std::string close_cmts = "-}", std::string quote_chars = "\"",
std::string multiline_quote = "\"\"\"");
const Lexem& next();
const Lexem& cur() const {
return lexem;
@ -109,6 +111,7 @@ class Lexer {
private:
void set_spec(std::array<int, 3>& arr, std::string setup);
bool is_multiline_quote(const char* begin, const char* end);
};
} // namespace src

View file

@ -2423,7 +2423,7 @@ std::vector<const src::FileDescr*> source_fdescr;
bool parse_source(std::istream* is, src::FileDescr* fdescr) {
src::SourceReader reader{is, fdescr};
src::Lexer lex{reader, true, "(){}:;? #$. ^~ #", "//", "/*", "*/"};
src::Lexer lex{reader, true, "(){}:;? #$. ^~ #", "//", "/*", "*/", ""};
while (lex.tp() != src::_Eof) {
parse_constructor_def(lex);
// std::cerr << lex.cur().str << '\t' << lex.cur().name_str() << std::endl;