diff --git a/src/lpython/parser/parser.yy b/src/lpython/parser/parser.yy index 7d773b962f..cd2b0ed95a 100644 --- a/src/lpython/parser/parser.yy +++ b/src/lpython/parser/parser.yy @@ -103,6 +103,9 @@ void yyerror(YYLTYPE *yyloc, LCompilers::LPython::Parser &p, const std::string & %token TK_CARET "^" %token TK_AT "@" %token TK_STRING +%token TK_FSTRING_START +%token TK_FSTRING_MIDDLE +%token TK_FSTRING_END %token TK_COMMENT %token TK_EOLCOMMENT %token TK_TYPE_COMMENT @@ -260,6 +263,8 @@ void yyerror(YYLTYPE *yyloc, LCompilers::LPython::Parser &p, const std::string & %type sep_one %type type_comment %type string +%type fstring +%type fstring_middle %type ternary_if_statement %type comprehension %type id_list @@ -1106,8 +1111,19 @@ subscript string : string TK_STRING { $$ = STRING2($1, $2, @$); } // TODO | string KW_STR_PREFIX TK_STRING { $$ = STRING4($1, STRING3($2, $3, @$), @$); } + | string fstring { $$ = STRING4($1, $2, @$); } | TK_STRING { $$ = STRING1($1, @$); } | KW_STR_PREFIX TK_STRING { $$ = STRING3($1, $2, @$); } + | fstring + ; + +fstring_middle + : fstring_middle TK_FSTRING_MIDDLE expr { $$ = FSTRING_MIDDLE($1, $2, $3, @$); } + | expr { $$ = FSTRING_MIDDLE1($1, @$); } + ; + +fstring + : TK_FSTRING_START fstring_middle TK_FSTRING_END { $$ = FSTRING($1, $2, $3, @$); } ; lambda_parameter diff --git a/src/lpython/parser/semantics.h b/src/lpython/parser/semantics.h index 9a41278783..8270b48bb1 100644 --- a/src/lpython/parser/semantics.h +++ b/src/lpython/parser/semantics.h @@ -802,10 +802,53 @@ static inline ast_t* concat_string(Allocator &al, Location &l, #define STRING2(x, y, l) concat_string(p.m_a, l, EXPR(x), str_unescape_c(p.m_a, y), nullptr) #define STRING3(prefix, x, l) PREFIX_STRING(p.m_a, l, prefix.c_str(p.m_a), x.c_str(p.m_a)) #define STRING4(x, s, l) concat_string(p.m_a, l, EXPR(x), "", EXPR(s)) +#define FSTRING(s, m, e, l) fstring(p.m_a, l, s.c_str(p.m_a), EXPR(m), e.c_str(p.m_a)) +#define FSTRING_MIDDLE(s, m, e, l) fstring_middle(p.m_a, l, EXPR(s), m.c_str(p.m_a), EXPR(e)) +#define FSTRING_MIDDLE1(x, l) fstring_middle1(p.m_a, l, EXPR(x)) #define FLOAT(x, l) make_ConstantFloat_t(p.m_a, l, x, nullptr) #define COMPLEX(x, l) make_ConstantComplex_t(p.m_a, l, 0, x, nullptr) #define BOOL(x, l) make_ConstantBool_t(p.m_a, l, x, nullptr) +static inline ast_t *fstring_middle1(Allocator &al, Location &l, expr_t *start){ + return make_FormattedValue_t(al, l, start, -1, nullptr); +} + +static inline ast_t *fstring_middle(Allocator &al, Location &l, expr_t *start, + char *middle, expr_t *end) { + Vec exprs; + exprs.reserve(al, 3); + exprs.push_back(al, start); + ast_t *tmp = make_ConstantStr_t(al, l, middle, nullptr); + exprs.push_back(al, EXPR(tmp)); + tmp = make_FormattedValue_t(al, l, end, -1, nullptr); + exprs.push_back(al, EXPR(tmp)); + tmp = make_JoinedStr_t(al, l, exprs.p, exprs.size()); + return tmp; +} + +static inline ast_t *fstring(Allocator &al, Location &l, char *start, + expr_t *middle, char *end) { + size_t p = 0, q = 0; + while(isalpha(start[p]) && p < strlen(start)) p++; + q = p; + while(start[q] == start[p] && q < strlen(start)) q++; + //discard the start prefix & quote & end brace characters, prefix can be 'r'|'f' + std::string str = std::string(start).substr(q, strlen(start)-q-1); + start = LCompilers::s2c(al, str); + str = std::string(end).substr(1, strlen(end)-(q-p)-1); + end = LCompilers::s2c(al, str); + + Vec exprs; + exprs.reserve(al, 3); + ast_t* tmp = make_ConstantStr_t(al, l, start, nullptr); + exprs.push_back(al, EXPR(tmp)); + exprs.push_back(al, middle); + tmp = make_ConstantStr_t(al, l, end, nullptr); + exprs.push_back(al, EXPR(tmp)); + tmp = make_JoinedStr_t(al, l, exprs.p, exprs.size()); + return tmp; +} + static inline ast_t *PREFIX_STRING(Allocator &al, Location &l, char *prefix, char *s){ Vec exprs; exprs.reserve(al, 4); @@ -818,49 +861,8 @@ static inline ast_t *PREFIX_STRING(Allocator &al, Location &l, char *prefix, cha } if (strcmp(prefix, "f") == 0 || strcmp(prefix, "fr") == 0 || strcmp(prefix, "rf") == 0) { - std::string str = std::string(s); - std::string s1 = "\""; - std::string id; - std::vector strs; - bool open_paren = false; - for (size_t i = 0; i < str.length(); i++) { - if(str[i] == '{') { - if(s1 != "\"") { - s1.push_back('"'); - strs.push_back(s1); - s1 = "\""; - } - open_paren = true; - } else if (str[i] != '}' && open_paren) { - id.push_back(s[i]); - } else if (str[i] == '}') { - if(id != "") { - strs.push_back(id); - id = ""; - } - open_paren = false; - } else if (!open_paren) { - s1.push_back(s[i]); - } - if(i == str.length()-1 && s1 != "\"") { - s1.push_back('"'); - strs.push_back(s1); - } - } - - for (size_t i = 0; i < strs.size(); i++) { - if (strs[i][0] == '"') { - strs[i] = strs[i].substr(1, strs[i].length() - 2); - tmp = make_ConstantStr_t(al, l, LCompilers::s2c(al, strs[i]), nullptr); - exprs.push_back(al, down_cast(tmp)); - } else { - tmp = make_Name_t(al, l, - LCompilers::s2c(al, strs[i]), expr_contextType::Load); - tmp = make_FormattedValue_t(al, l, EXPR(tmp), -1, nullptr); - exprs.push_back(al, down_cast(tmp)); - } - } - tmp = make_JoinedStr_t(al, l, exprs.p, exprs.size()); + // ignore 'f', assuming it is handled by fstring + tmp = make_ConstantStr_t(al, l, s, nullptr); } else if (strcmp(prefix, "b") == 0) { LCompilers::Str s_; s_.from_str(al, std::string(s)); diff --git a/src/lpython/parser/tokenizer.h b/src/lpython/parser/tokenizer.h index 3fe00226bb..e42d4c39db 100644 --- a/src/lpython/parser/tokenizer.h +++ b/src/lpython/parser/tokenizer.h @@ -20,7 +20,7 @@ class Tokenizer uint32_t prev_loc; // The previous file ended at this location. int last_token=-1; - + int fstring_flag = 0; bool indent = false; // Next line is expected to be indented int dedent = 0; // Allowed values: 0, 1, 2, see the code below the meaning of this state variable bool colon_actual_last_token = false; // If the actual last token was a colon @@ -79,6 +79,7 @@ class Tokenizer void lex_match_or_case(Location &loc, unsigned char *cur, bool &is_match_or_case_keyword); + int lex_fstring(Location &loc, unsigned char * &cur, YYSTYPE &yylval); }; std::string token2text(const int token); diff --git a/src/lpython/parser/tokenizer.re b/src/lpython/parser/tokenizer.re index 64b0488b76..a6445c2f5e 100644 --- a/src/lpython/parser/tokenizer.re +++ b/src/lpython/parser/tokenizer.re @@ -290,6 +290,37 @@ int Tokenizer::lex(Allocator &al, YYSTYPE &yylval, Location &loc, diag::Diagnost | ("''" | "''" "\\"+) [^'\x00\\] | [^'\x00\\] )* "'''"; + + fstring_format1 = ('\\'[^\x00{}] | [^"\x00\n\\{}])*; + fstring_format2 = ("\\"[^\x00{}] | [^'\x00\n\\{}])*; + fstring_format3 = ( '\\'[^\x00{}] + | ('"' | '"' '\\'+ '"' | '"' '\\'+) [^"\x00\\{}] + | ('""' | '""' '\\'+) [^"\x00\\{}] + | [^"\x00\\{}] )*; + fstring_format4 = ( "\\"[^\x00{}] + | ("'" | "'" "\\"+ "'" | "'" "\\"+) [^'\x00\\{}] + | ("''" | "''" "\\"+) [^'\x00\\{}] + | [^'\x00\\{}] )*; + + fstring_prefix = ([fF] | [fF][rR] | [rR][fF]); + fstring_start1 = fstring_prefix '"' fstring_format1 '{'; + fstring_start2 = fstring_prefix "'" fstring_format2 '{'; + fstring_start3 = fstring_prefix '"""' fstring_format3 '{'; + fstring_start4 = fstring_prefix "'''" fstring_format4 '{'; + + fstring_start1 { + fstring_flag = 1; token(yylval.string); RET(TK_FSTRING_START) + } + fstring_start2 { + fstring_flag = 2; token(yylval.string); RET(TK_FSTRING_START) + } + fstring_start3 { + fstring_flag = 3; token(yylval.string); RET(TK_FSTRING_START) + } + fstring_start4 { + fstring_flag = 4; token(yylval.string); RET(TK_FSTRING_START) + } + type_ignore = "#" whitespace? "type:" whitespace? "ignore" [^\n\x00]*; type_comment = "#" whitespace? "type:" whitespace? [^\n\x00]*; comment = "#" [^\n\x00]*; @@ -305,6 +336,7 @@ int Tokenizer::lex(Allocator &al, YYSTYPE &yylval, Location &loc, diag::Diagnost }) ); } + end { token_loc(loc); if(parenlevel) { @@ -434,10 +466,10 @@ int Tokenizer::lex(Allocator &al, YYSTYPE &yylval, Location &loc, diag::Diagnost RET(TK_NAME); } } - + [rR][bB] | [bB][rR] | [fF][rR] | [rR][fF] - | [rR] | [bB] | [fF] | [uU] + | [rR] | [fF] | [bB] | [uU] { if(cur[0] == '\'' || cur[0] == '"'){ KW(STR_PREFIX); @@ -472,7 +504,13 @@ int Tokenizer::lex(Allocator &al, YYSTYPE &yylval, Location &loc, diag::Diagnost "{" { token_loc(loc); record_paren(loc, '{'); RET(TK_LBRACE) } ")" { token_loc(loc); record_paren(loc, ')'); RET(TK_RPAREN) } "]" { token_loc(loc); record_paren(loc, ']'); RET(TK_RBRACKET) } - "}" { token_loc(loc); record_paren(loc, '}'); RET(TK_RBRACE) } + "}" { + if(fstring_flag >= 1){ + return lex_fstring(loc, cur, yylval); + }else{ + token_loc(loc); record_paren(loc, '}'); RET(TK_RBRACE) + } + } "+" { RET(TK_PLUS) } "-" { RET(TK_MINUS) } "=" { RET(TK_EQUAL) } @@ -606,6 +644,95 @@ int Tokenizer::lex(Allocator &al, YYSTYPE &yylval, Location &loc, diag::Diagnost } } +int Tokenizer::lex_fstring(Location &loc, unsigned char * &cur, YYSTYPE &yylval){ + unsigned char *mar; + + /*!re2c + re2c:define:YYCURSOR = cur; + re2c:define:YYMARKER = mar; + re2c:yyfill:enable = 0; + re2c:define:YYCTYPE = "unsigned char"; + + //fstring_format1 = ('\\'[^\x00{}] | [^"\x00\n\\{}])*; + //fstring_format2 = ( "\\"[^\x00{}] + // | ("'" | "'" "\\"+ "'" | "'" "\\"+) [^'\x00\\{}] + // | ("''" | "''" "\\"+) [^'\x00\\{}] + // | [^'\x00\\{}] )*; + */ + switch(fstring_flag){ + case 1: goto fstring1; + case 2: goto fstring2; + case 3: goto fstring3; + case 4: goto fstring4; + default: return -1; + } +fstring1: + /*!re2c + fstring_middle1 = fstring_format1 "{"; + fstring_end1 = fstring_format1 '"'; + + fstring_middle1 { + token_loc(loc); + token_str(yylval.string); + RET(TK_FSTRING_MIDDLE) + } + fstring_end1 { token_loc(loc); fstring_flag = 0; token(yylval.string); RET(TK_FSTRING_END) } + * { goto default_rule; } + */ +fstring2: + /*!re2c + fstring_middle2 = fstring_format2 "{"; + fstring_end2 = fstring_format2 "'"; + fstring_middle2 { + token_loc(loc); + token_str(yylval.string); + RET(TK_FSTRING_MIDDLE) + } + fstring_end2 { token_loc(loc); fstring_flag = 0; token(yylval.string); RET(TK_FSTRING_END) } + * { goto default_rule; } + */ +fstring3: + /*!re2c + fstring_middle3 = fstring_format3 "{"; + fstring_end3 = fstring_format3 '"""'; + fstring_middle3 { + token_loc(loc); + token_str(yylval.string); + RET(TK_FSTRING_MIDDLE) + } + fstring_end3 { token_loc(loc); fstring_flag = 0; token(yylval.string); RET(TK_FSTRING_END) } + * { goto default_rule; } + */ +fstring4: + /*!re2c + fstring_middle4 = fstring_format4 "{"; + fstring_end4 = fstring_format4 "'''"; + fstring_middle4 { + token_loc(loc); + token_str(yylval.string); + RET(TK_FSTRING_MIDDLE) + } + fstring_end4 { token_loc(loc); fstring_flag = 0; token(yylval.string); RET(TK_FSTRING_END) } + * { goto default_rule; } + */ +default_rule: + /*!re2c + * { + token_loc(loc); + std::string t = std::string((char *)tok, cur - tok); + throw parser_local::TokenizerError("Token '" + + t + "' is not recognized in `fstring` statement", loc); + } + end { + token_loc(loc); + std::string t = std::string((char *)tok, cur - tok); + throw parser_local::TokenizerError( + "End of file not expected within `fstring` statement: '" + t + + "'", loc); + } + */ +} + void Tokenizer::lex_match_or_case(Location &loc, unsigned char *cur, bool &is_match_or_case_keyword) { for (;;) { @@ -700,6 +827,9 @@ std::string token2text(const int token) T(TK_AT, "@") T(TK_STRING, "string") + T(TK_FSTRING_START, "fstring_start") + T(TK_FSTRING_MIDDLE, "fstring_middle") + T(TK_FSTRING_END, "fstring_end") T(TK_COMMENT, "comment") T(TK_EOLCOMMENT, "eolcomment") T(TK_TYPE_COMMENT, "type_comment") @@ -838,7 +968,8 @@ std::string pickle_token(int token, const YYSTYPE &yystype) t += " " + std::to_string(yystype.f); } else if (token == yytokentype::TK_IMAG_NUM) { t += " " + std::to_string(yystype.f) + "j"; - } else if (token == yytokentype::TK_STRING) { + } else if (token == yytokentype::TK_STRING || token == yytokentype::TK_FSTRING_START + || token == yytokentype::TK_FSTRING_MIDDLE || token == yytokentype::TK_FSTRING_END) { t = t + " " + "\"" + str_escape_c(yystype.string.str()) + "\""; } else if (token == yytokentype::TK_TYPE_COMMENT) { t = t + " " + "\"" + yystype.string.str() + "\""; diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 4e11fe01ed..f238eb0c41 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3352,6 +3352,30 @@ class CommonVisitor : public AST::BaseVisitor { } tmp = ASR::make_LogicalBinOp_t(al, x.base.base.loc, lhs, op, rhs, dest_type, value); } + + void visit_FormattedValue(const AST::FormattedValue_t &x){ + this->visit_expr(*x.m_value); + // converting x as call_arg for the handle_intrinsic_str function + ASR::expr_t* expr = ASRUtils::EXPR(tmp); + ASR::call_arg_t arg; + arg.loc = expr->base.loc; + arg.m_value = expr; + Vec call_args; + call_args.reserve(al, 1); + call_args.push_back(al, arg); + tmp = intrinsic_node_handler.handle_intrinsic_str(al, call_args, x.base.base.loc); + } + + void visit_JoinedStr(const AST::JoinedStr_t &x){ + this->visit_expr(*x.m_values[0]); + ASR::expr_t *left = ASRUtils::EXPR(tmp); + for(size_t i = 1; i < x.n_values; i++){ + this->visit_expr(*x.m_values[i]); + ASR::expr_t *right = ASRUtils::EXPR(tmp); + make_BinOp_helper(left, right, ASR::binopType::Add, x.base.base.loc); + left = ASRUtils::EXPR(tmp); + } + } void visit_BinOp(const AST::BinOp_t &x) { this->visit_expr(*x.m_left); diff --git a/tests/fstring1.py b/tests/fstring1.py new file mode 100644 index 0000000000..d631cbca69 --- /dev/null +++ b/tests/fstring1.py @@ -0,0 +1,19 @@ +a : str = "FooBar" +b : i32 = 10 +c : i32 = 11 +print(f"{b} + 1 = {c}") # int inside fstring +print(f"Say something! {a}") # string inside fstring +print(f"do some calculation: {b*7+c}") # expression inside fstring +print("9..." f"{b}...{c}") # concatenation of normal string with fstring +print(f"{b}...{c}..." "12" ) # concatenation of normal string with fstring +print(f"{b} " f"{c}") # concatenation of fstrings +print(fR"Hello! {a}") +print(rF""" + Something fun! {a*2} +""") +print(Fr''' + Something fun! {c} +''') +print(F"""Hello World {b} {c}""") +print(r"LEFT " f"RIGHT") +print(f"THIS " r"THAT") \ No newline at end of file diff --git a/tests/reference/asr-fstring1-d96758f.json b/tests/reference/asr-fstring1-d96758f.json new file mode 100644 index 0000000000..6b8f60edae --- /dev/null +++ b/tests/reference/asr-fstring1-d96758f.json @@ -0,0 +1,13 @@ +{ + "basename": "asr-fstring1-d96758f", + "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", + "infile": "tests/fstring1.py", + "infile_hash": "ddceb6a09b5bc556ae8d2db18908c8f60af3ee96cc971bed1f5f9ae9", + "outfile": null, + "outfile_hash": null, + "stdout": "asr-fstring1-d96758f.stdout", + "stdout_hash": "c19f804850e02097002f4c40c7a990738d19f28aed1486010de3ee2b", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/asr-fstring1-d96758f.stdout b/tests/reference/asr-fstring1-d96758f.stdout new file mode 100644 index 0000000000..5ff7707e0a --- /dev/null +++ b/tests/reference/asr-fstring1-d96758f.stdout @@ -0,0 +1,522 @@ +(TranslationUnit + (SymbolTable + 1 + { + __main__: + (Module + (SymbolTable + 2 + { + __main__global_stmts: + (Function + (SymbolTable + 3 + { + + }) + __main__global_stmts + (FunctionType + [] + () + Source + Implementation + () + .false. + .false. + .false. + .false. + .false. + [] + .false. + ) + [] + [] + [(Print + [(StringConcat + (StringConcat + (StringConstant + "" + (Character 1 0 ()) + ) + (StringConcat + (StringConcat + (Cast + (Var 2 b) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (StringConstant + " + 1 = " + (Character 1 7 ()) + ) + (Character 1 5 ()) + () + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 3 ()) + () + ) + (Character 1 3 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 3 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "Say something! " + (Character 1 15 ()) + ) + (Var 2 a) + (Character 1 13 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 13 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "do some calculation: " + (Character 1 21 ()) + ) + (Cast + (IntegerBinOp + (IntegerBinOp + (Var 2 b) + Mul + (IntegerConstant 7 (Integer 4)) + (Integer 4) + () + ) + Add + (Var 2 c) + (Integer 4) + () + ) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 19 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 19 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConcat + (StringConstant + "9..." + (Character 1 4 ()) + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 4 ()) + (StringConstant + "9..." + (Character 1 4 ()) + ) + ) + (StringConcat + (StringConcat + (Cast + (Var 2 b) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (StringConstant + "..." + (Character 1 3 ()) + ) + (Character 1 1 ()) + () + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 -1 ()) + () + ) + (Character 1 3 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 3 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConcat + (StringConstant + "" + (Character 1 0 ()) + ) + (StringConcat + (StringConcat + (Cast + (Var 2 b) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (StringConstant + "..." + (Character 1 3 ()) + ) + (Character 1 1 ()) + () + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 -1 ()) + () + ) + (Character 1 -1 ()) + () + ) + (StringConstant + "..." + (Character 1 3 ()) + ) + (Character 1 2 ()) + () + ) + (StringConstant + "12" + (Character 1 2 ()) + ) + (Character 1 4 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConcat + (StringConcat + (StringConcat + (StringConstant + "" + (Character 1 0 ()) + ) + (Cast + (Var 2 b) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 -2 ()) + () + ) + (StringConstant + " " + (Character 1 1 ()) + ) + (Character 1 -1 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 -1 ()) + () + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 -3 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 -3 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "Hello! " + (Character 1 7 ()) + ) + (Var 2 a) + (Character 1 5 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 5 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "\n Something fun! " + (Character 1 17 ()) + ) + (StringRepeat + (Var 2 a) + (IntegerConstant 2 (Integer 4)) + (Character 1 0 ()) + () + ) + (Character 1 17 ()) + () + ) + (StringConstant + "\n" + (Character 1 1 ()) + ) + (Character 1 18 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "\n Something fun! " + (Character 1 17 ()) + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 15 ()) + () + ) + (StringConstant + "\n" + (Character 1 1 ()) + ) + (Character 1 16 ()) + () + )] + () + () + ) + (Print + [(StringConcat + (StringConcat + (StringConstant + "Hello World " + (Character 1 12 ()) + ) + (StringConcat + (StringConcat + (Cast + (Var 2 b) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (StringConstant + " " + (Character 1 1 ()) + ) + (Character 1 -1 ()) + () + ) + (Cast + (Var 2 c) + IntegerToCharacter + (Character 1 -2 ()) + () + ) + (Character 1 -3 ()) + () + ) + (Character 1 9 ()) + () + ) + (StringConstant + "" + (Character 1 0 ()) + ) + (Character 1 9 ()) + () + )] + () + () + ) + (Print + [(StringConstant + "LEFT RIGHT" + (Character 1 10 ()) + )] + () + () + ) + (Print + [(StringConstant + "THIS THAT" + (Character 1 9 ()) + )] + () + () + )] + () + Public + .false. + .false. + () + ), + a: + (Variable + 2 + a + [] + Local + (StringConstant + "FooBar" + (Character 1 6 ()) + ) + (StringConstant + "FooBar" + (Character 1 6 ()) + ) + Default + (Character 1 -2 ()) + () + Source + Public + Required + .false. + ), + b: + (Variable + 2 + b + [] + Local + (IntegerConstant 10 (Integer 4)) + (IntegerConstant 10 (Integer 4)) + Default + (Integer 4) + () + Source + Public + Required + .false. + ), + c: + (Variable + 2 + c + [] + Local + (IntegerConstant 11 (Integer 4)) + (IntegerConstant 11 (Integer 4)) + Default + (Integer 4) + () + Source + Public + Required + .false. + ) + }) + __main__ + [] + .false. + .false. + ), + main_program: + (Program + (SymbolTable + 4 + { + __main__global_stmts: + (ExternalSymbol + 4 + __main__global_stmts + 2 __main__global_stmts + __main__ + [] + __main__global_stmts + Public + ) + }) + main_program + [__main__] + [(SubroutineCall + 4 __main__global_stmts + 2 __main__global_stmts + [] + () + )] + ) + }) + [] +) diff --git a/tests/reference/ast-fstring1-8d426c9.json b/tests/reference/ast-fstring1-8d426c9.json new file mode 100644 index 0000000000..a21562e47c --- /dev/null +++ b/tests/reference/ast-fstring1-8d426c9.json @@ -0,0 +1,13 @@ +{ + "basename": "ast-fstring1-8d426c9", + "cmd": "lpython --show-ast --no-color {infile} -o {outfile}", + "infile": "tests/fstring1.py", + "infile_hash": "ddceb6a09b5bc556ae8d2db18908c8f60af3ee96cc971bed1f5f9ae9", + "outfile": null, + "outfile_hash": null, + "stdout": "ast-fstring1-8d426c9.stdout", + "stdout_hash": "c85f68a44e23e21912b4bd4d8e0e21d5542d76879ade0ae2dbd362d0", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/ast-fstring1-8d426c9.stdout b/tests/reference/ast-fstring1-8d426c9.stdout new file mode 100644 index 0000000000..7ade8e6612 --- /dev/null +++ b/tests/reference/ast-fstring1-8d426c9.stdout @@ -0,0 +1,445 @@ +(Module + [(AnnAssign + (Name + a + Store + ) + (Name + str + Load + ) + (ConstantStr + "FooBar" + () + ) + 1 + ) + (AnnAssign + (Name + b + Store + ) + (Name + i32 + Load + ) + (ConstantInt + 10 + () + ) + 1 + ) + (AnnAssign + (Name + c + Store + ) + (Name + i32 + Load + ) + (ConstantInt + 11 + () + ) + 1 + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "" + () + ) + (JoinedStr + [(FormattedValue + (Name + b + Load + ) + -1 + () + ) + (ConstantStr + " + 1 = " + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + )] + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "Say something! " + () + ) + (FormattedValue + (Name + a + Load + ) + -1 + () + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "do some calculation: " + () + ) + (FormattedValue + (BinOp + (BinOp + (Name + b + Load + ) + Mult + (ConstantInt + 7 + () + ) + ) + Add + (Name + c + Load + ) + ) + -1 + () + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "9..." + () + ) + (ConstantStr + "" + () + ) + (JoinedStr + [(FormattedValue + (Name + b + Load + ) + -1 + () + ) + (ConstantStr + "..." + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + )] + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "" + () + ) + (JoinedStr + [(FormattedValue + (Name + b + Load + ) + -1 + () + ) + (ConstantStr + "..." + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + )] + ) + (ConstantStr + "..." + () + ) + (ConstantStr + "12" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "" + () + ) + (FormattedValue + (Name + b + Load + ) + -1 + () + ) + (ConstantStr + " " + () + ) + (ConstantStr + "" + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "Hello! " + () + ) + (FormattedValue + (Name + a + Load + ) + -1 + () + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "\n Something fun! " + () + ) + (FormattedValue + (BinOp + (Name + a + Load + ) + Mult + (ConstantInt + 2 + () + ) + ) + -1 + () + ) + (ConstantStr + "\n" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "\n Something fun! " + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + ) + (ConstantStr + "\n" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(JoinedStr + [(ConstantStr + "Hello World " + () + ) + (JoinedStr + [(FormattedValue + (Name + b + Load + ) + -1 + () + ) + (ConstantStr + " " + () + ) + (FormattedValue + (Name + c + Load + ) + -1 + () + )] + ) + (ConstantStr + "" + () + )] + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(ConstantStr + "LEFT RIGHT" + () + )] + [] + ) + ) + (Expr + (Call + (Name + print + Load + ) + [(ConstantStr + "THIS THAT" + () + )] + [] + ) + )] + [] +) diff --git a/tests/reference/ast_new-match_stmt1-9e84d24.json b/tests/reference/ast_new-match_stmt1-9e84d24.json index 6e096f25ea..dae186aea1 100644 --- a/tests/reference/ast_new-match_stmt1-9e84d24.json +++ b/tests/reference/ast_new-match_stmt1-9e84d24.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "ast_new-match_stmt1-9e84d24.stdout", - "stdout_hash": "8e43bb4b05ebab0df9520dac9908702af0d2e7f63ddb42bf93baf0a0", + "stdout_hash": "db40dd3e23c2d07d8348a6c09d60b4feb44a9decbb4b8d4dc059227b", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast_new-match_stmt1-9e84d24.stdout b/tests/reference/ast_new-match_stmt1-9e84d24.stdout index f368aa9399..6b0258f4a4 100644 --- a/tests/reference/ast_new-match_stmt1-9e84d24.stdout +++ b/tests/reference/ast_new-match_stmt1-9e84d24.stdout @@ -1701,8 +1701,12 @@ () ) (FormattedValue - (Name - cls.__name__ + (Attribute + (Name + cls + Load + ) + __name__ Load ) -1 diff --git a/tests/reference/ast_new-string1-96b90b3.json b/tests/reference/ast_new-string1-96b90b3.json index 49a78caf38..0e76f28484 100644 --- a/tests/reference/ast_new-string1-96b90b3.json +++ b/tests/reference/ast_new-string1-96b90b3.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "ast_new-string1-96b90b3.stdout", - "stdout_hash": "51806e5893017a386c0ce7a4f3260c7605cabd5ea4e6a16aa300d8c2", + "stdout_hash": "e501ed60d013bcbd95182958e0c49f4a15083c2601230259958c25b6", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/ast_new-string1-96b90b3.stdout b/tests/reference/ast_new-string1-96b90b3.stdout index cc011f29f2..3eaafeaceb 100644 --- a/tests/reference/ast_new-string1-96b90b3.stdout +++ b/tests/reference/ast_new-string1-96b90b3.stdout @@ -5,37 +5,41 @@ "Hello, " () ) - (FormattedValue - (Name - first_name - Load - ) - -1 - () - ) - (ConstantStr - " " - () - ) - (FormattedValue - (Name - last_name - Load + (JoinedStr + [(JoinedStr + [(FormattedValue + (Name + first_name + Load + ) + -1 + () + ) + (ConstantStr + " " + () + ) + (FormattedValue + (Name + last_name + Load + ) + -1 + () + )] ) - -1 - () - ) - (ConstantStr - ". You are " - () - ) - (FormattedValue - (Name - age - Load + (ConstantStr + ". You are " + () ) - -1 - () + (FormattedValue + (Name + age + Load + ) + -1 + () + )] ) (ConstantStr " years old." @@ -50,25 +54,31 @@ Load ) [(JoinedStr - [(FormattedValue - (Name - __file__ - Load - ) - -1 - () - ) - (ConstantStr - " executed in " + [(ConstantStr + "" () ) - (FormattedValue - (Name - elapsed - Load + (JoinedStr + [(FormattedValue + (Name + __file__ + Load + ) + -1 + () ) - -1 - () + (ConstantStr + " executed in " + () + ) + (FormattedValue + (Name + elapsed + Load + ) + -1 + () + )] ) (ConstantStr " seconds." @@ -145,6 +155,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -161,6 +175,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -177,6 +195,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -193,6 +215,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -209,6 +235,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -245,6 +275,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -261,6 +295,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -325,6 +363,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -334,24 +376,30 @@ "Text" () ) - (FormattedValue - (Name - a - Load + (JoinedStr + [(FormattedValue + (Name + a + Load + ) + -1 + () ) - -1 - () + (ConstantStr + ", " + () + ) + (FormattedValue + (Name + b + Load + ) + -1 + () + )] ) (ConstantStr - ", " - () - ) - (FormattedValue - (Name - b - Load - ) - -1 + "" () ) (ConstantStr @@ -365,6 +413,10 @@ ) -1 () + ) + (ConstantStr + "" + () )] ) ) @@ -374,24 +426,30 @@ "Text" () ) - (FormattedValue - (Name - a - Load + (JoinedStr + [(FormattedValue + (Name + a + Load + ) + -1 + () ) - -1 - () + (ConstantStr + ", " + () + ) + (FormattedValue + (Name + b + Load + ) + -1 + () + )] ) (ConstantStr - ", " - () - ) - (FormattedValue - (Name - b - Load - ) - -1 + "" () ) (ConstantStr @@ -406,6 +464,10 @@ "Text" () ) + (ConstantStr + "" + () + ) (FormattedValue (Name b @@ -434,6 +496,10 @@ -1 () ) + (ConstantStr + "" + () + ) (ConstantStr "Text" () @@ -458,6 +524,10 @@ "Text" () ) + (ConstantStr + "" + () + ) (FormattedValue (Name a @@ -497,11 +567,9 @@ ) ) (Expr - (JoinedStr - [(ConstantStr - "\\n" - () - )] + (ConstantStr + "\\n" + () ) ) (Expr diff --git a/tests/reference/runtime-fstring1-20a9192.json b/tests/reference/runtime-fstring1-20a9192.json new file mode 100644 index 0000000000..d429811eab --- /dev/null +++ b/tests/reference/runtime-fstring1-20a9192.json @@ -0,0 +1,13 @@ +{ + "basename": "runtime-fstring1-20a9192", + "cmd": "lpython {infile}", + "infile": "tests/fstring1.py", + "infile_hash": "ddceb6a09b5bc556ae8d2db18908c8f60af3ee96cc971bed1f5f9ae9", + "outfile": null, + "outfile_hash": null, + "stdout": "runtime-fstring1-20a9192.stdout", + "stdout_hash": "2c65ae0b9a4e18369a1421c44c5269ddd5a2c57e86f598b1a35ef4b1", + "stderr": null, + "stderr_hash": null, + "returncode": 0 +} \ No newline at end of file diff --git a/tests/reference/runtime-fstring1-20a9192.stdout b/tests/reference/runtime-fstring1-20a9192.stdout new file mode 100644 index 0000000000..f5d29ef6fc --- /dev/null +++ b/tests/reference/runtime-fstring1-20a9192.stdout @@ -0,0 +1,16 @@ +10 + 1 = 11 +Say something! FooBar +do some calculation: 81 +9...10...11 +10...11...12 +10 11 +Hello! FooBar + + Something fun! FooBarFooBar + + + Something fun! 11 + +Hello World 10 11 +LEFT RIGHT +THIS THAT diff --git a/tests/tests.toml b/tests/tests.toml index 4f048e910b..0f15500c27 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -142,6 +142,12 @@ asr = true llvm = true llvm_dbg = true +[[test]] +filename = "fstring1.py" +ast = true +asr = true +run = true + [[test]] filename = "../integration_tests/array_01_decl.py" asr = true