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:
parent
e913871f4f
commit
d23267d996
6 changed files with 123 additions and 13 deletions
|
@ -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)) {
|
||||
|
|
|
@ -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
26
crypto/func/test/s2.fc
Normal 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"));
|
||||
}
|
|
@ -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 == '`') {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue