Skip to content

Commit

Permalink
Merge pull request lcompilers#624 from akshanshbhatt/fstring
Browse files Browse the repository at this point in the history
[Parser] Add support for parsing prefixed strings
  • Loading branch information
certik authored Jun 20, 2022
2 parents 32c1736 + 138d1c3 commit 4bbfb17
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lpython/parser/parser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,8 @@ function_call
string
: string TK_STRING { $$ = STRING2($1, $2, @$); } // TODO
| TK_STRING { $$ = STRING1($1, @$); }
| id TK_STRING { $$ = STRING3($1, $2, @$); }
;

expr
: id { $$ = $1; }
Expand Down
52 changes: 52 additions & 0 deletions src/lpython/parser/semantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,10 +429,62 @@ char* concat_string(Allocator &al, ast_t *a, char *b) {
#define INTEGER(x, l) make_ConstantInt_t(p.m_a, l, x, nullptr)
#define STRING1(x, l) make_ConstantStr_t(p.m_a, l, x.c_str(p.m_a), nullptr)
#define STRING2(x, y, l) make_ConstantStr_t(p.m_a, l, concat_string(p.m_a, x, y.c_str(p.m_a)), nullptr)
#define STRING3(id, x, l) PREFIX_STRING(p.m_a, l, name2char(id), x.c_str(p.m_a))
#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 *PREFIX_STRING(Allocator &al, Location &l, char *prefix, char *s){
Vec<expr_t *> exprs;
exprs.reserve(al, 4);
ast_t *tmp;
if (strcmp(prefix, "f") == 0) {
std::string str = std::string(s);
std::string s1 = "\"";
std::string id;
std::vector<std::string> 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, LFortran::s2c(al, strs[i]), nullptr);
exprs.push_back(al, down_cast<expr_t>(tmp));
} else {
tmp = make_Name_t(al, l,
LFortran::s2c(al, strs[i]), expr_contextType::Load);
tmp = make_FormattedValue_t(al, l, EXPR(tmp), -1, nullptr);
exprs.push_back(al, down_cast<expr_t>(tmp));
}
}
}
return make_JoinedStr_t(al, l, exprs.p, exprs.size());
}

static inline keyword_t *CALL_KW(Allocator &al, Location &l,
char *arg, expr_t* val) {
keyword_t *r = al.allocate<keyword_t>();
Expand Down
7 changes: 7 additions & 0 deletions tests/parser/string1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
f"Hello, {first_name} {last_name}. You are {age} years old."

print(f"{__file__} executed in {elapsed} seconds.")

# TODO: Support format specifiers

# print(f"{__file__} executed in {elapsed:0.2f} seconds.")
13 changes: 13 additions & 0 deletions tests/reference/ast_new-string1-96b90b3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "ast_new-string1-96b90b3",
"cmd": "lpython --show-ast --new-parser --no-color {infile} -o {outfile}",
"infile": "tests/parser/string1.py",
"infile_hash": "e51ab7a60ad39354a13d987f0ed3bdb8f51b8e6d2a677a9d7b720749",
"outfile": null,
"outfile_hash": null,
"stdout": "ast_new-string1-96b90b3.stdout",
"stdout_hash": "00a9b4899bd6ba7938b503da224840f51e2e7ba2e41121292809bdf2",
"stderr": null,
"stderr_hash": null,
"returncode": 0
}
1 change: 1 addition & 0 deletions tests/reference/ast_new-string1-96b90b3.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(Module [(Expr (JoinedStr [(ConstantStr "Hello, " ()) (FormattedValue (Name first_name Load) -1 ()) (ConstantStr " " ()) (FormattedValue (Name last_name Load) -1 ()) (ConstantStr ". You are " ()) (FormattedValue (Name age Load) -1 ()) (ConstantStr " years old." ())])) (Expr (Call (Name print Load) [(JoinedStr [(FormattedValue (Name __file__ Load) -1 ()) (ConstantStr " executed in " ()) (FormattedValue (Name elapsed Load) -1 ()) (ConstantStr " seconds." ())])] []))] [])
4 changes: 4 additions & 0 deletions tests/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@ ast_new = true
filename = "parser/while1.py"
ast_new = true

[[test]]
filename = "parser/string1.py"
ast_new = true

# tests/errors

[[test]]
Expand Down

0 comments on commit 4bbfb17

Please sign in to comment.