Skip to content

Commit a9d4ca9

Browse files
author
Lars Berscheid
committed
fix string view reference movement in bytecode
1 parent 699c207 commit a9d4ca9

File tree

8 files changed

+49
-54
lines changed

8 files changed

+49
-54
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ The environment class can be configured to your needs.
8282
Environment env_default;
8383
8484
// With global path to template files and where files will be saved
85-
Environment env_1 = Environment("../path/templates/");
85+
Environment env_1 {"../path/templates/"};
8686
8787
// With separate input and output path
88-
Environment env_2 = Environment("../path/templates/", "../path/results/");
88+
Environment env_2 {"../path/templates/", "../path/results/"};
8989
9090
// Choose between dot notation (like Jinja2) and JSON pointer to access elements
9191
env.set_element_notation(ElementNotation::Dot); // (default) e.g. time.start

include/inja/bytecode.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ struct Bytecode {
116116
uint32_t flags: 2;
117117

118118
json value;
119-
std::string_view str;
119+
std::string str;
120120

121121
Bytecode(): args(0), flags(0) {}
122122
explicit Bytecode(Op op, unsigned int args = 0): op(op), args(args), flags(0) {}

include/inja/lexer.hpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,28 @@ class Lexer {
208208

209209
Token scan_id() {
210210
for (;;) {
211-
if (m_pos >= m_in.size()) break;
211+
if (m_pos >= m_in.size()) {
212+
break;
213+
}
212214
char ch = m_in[m_pos];
213-
if (!std::isalnum(ch) && ch != '.' && ch != '/' && ch != '_' && ch != '-') break;
215+
if (!std::isalnum(ch) && ch != '.' && ch != '/' && ch != '_' && ch != '-') {
216+
break;
217+
}
214218
m_pos += 1;
215219
}
216220
return make_token(Token::Kind::Id);
217221
}
218222

219223
Token scan_number() {
220224
for (;;) {
221-
if (m_pos >= m_in.size()) break;
225+
if (m_pos >= m_in.size()) {
226+
break;
227+
}
222228
char ch = m_in[m_pos];
223229
// be very permissive in lexer (we'll catch errors when conversion happens)
224-
if (!std::isdigit(ch) && ch != '.' && ch != 'e' && ch != 'E' && ch != '+' && ch != '-')
230+
if (!std::isdigit(ch) && ch != '.' && ch != 'e' && ch != 'E' && ch != '+' && ch != '-') {
225231
break;
232+
}
226233
m_pos += 1;
227234
}
228235
return make_token(Token::Kind::Number);
@@ -233,12 +240,13 @@ class Lexer {
233240
for (;;) {
234241
if (m_pos >= m_in.size()) break;
235242
char ch = m_in[m_pos++];
236-
if (ch == '\\')
243+
if (ch == '\\') {
237244
escape = true;
238-
else if (!escape && ch == m_in[m_tok_start])
245+
} else if (!escape && ch == m_in[m_tok_start]) {
239246
break;
240-
else
247+
} else {
241248
escape = false;
249+
}
242250
}
243251
return make_token(Token::Kind::String);
244252
}

include/inja/parser.hpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,6 @@ class Parser {
381381
}
382382
// sys::path::remove_dots(pathname, true, sys::path::Style::posix);
383383

384-
// parse it only if it's new
385-
// TemplateStorage::iterator included;
386-
// bool is_new {true};
387-
// std::tie(included, is_new) = m_included_templates.emplace(pathname);
388-
// if (is_new) included->second = parse_template(pathname);
389-
390384
Template include_template = parse_template(pathname);
391385
m_included_templates.emplace(pathname, include_template);
392386

include/inja/renderer.hpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ class Renderer {
2828
std::vector<const json*>& get_args(const Bytecode& bc) {
2929
m_tmp_args.clear();
3030

31-
bool hasImm = ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop);
31+
bool has_imm = ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop);
3232

3333
// get args from stack
3434
unsigned int pop_args = bc.args;
35-
if (hasImm) --pop_args;
35+
if (has_imm) {
36+
pop_args -= 1;
37+
}
3638

3739
for (auto i = std::prev(m_stack.end(), pop_args); i != m_stack.end(); i++) {
3840
m_tmp_args.push_back(&(*i));
3941
}
4042

4143
// get immediate arg
42-
if (hasImm) {
44+
if (has_imm) {
4345
m_tmp_args.push_back(get_imm(bc));
4446
}
4547

@@ -48,9 +50,12 @@ class Renderer {
4850

4951
void pop_args(const Bytecode& bc) {
5052
unsigned int popArgs = bc.args;
51-
if ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop)
52-
--popArgs;
53-
for (unsigned int i = 0; i < popArgs; ++i) m_stack.pop_back();
53+
if ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop) {
54+
popArgs -= 1;
55+
}
56+
for (unsigned int i = 0; i < popArgs; ++i) {
57+
m_stack.pop_back();
58+
}
5459
}
5560

5661
const json* get_imm(const Bytecode& bc) {
@@ -169,11 +174,13 @@ class Renderer {
169174
const auto& bc = tmpl.bytecodes[i];
170175

171176
switch (bc.op) {
172-
case Bytecode::Op::Nop:
177+
case Bytecode::Op::Nop: {
173178
break;
174-
case Bytecode::Op::PrintText:
179+
}
180+
case Bytecode::Op::PrintText: {
175181
os << bc.str;
176182
break;
183+
}
177184
case Bytecode::Op::PrintValue: {
178185
const json& val = *get_args(bc)[0];
179186
if (val.is_string())
@@ -184,9 +191,10 @@ class Renderer {
184191
pop_args(bc);
185192
break;
186193
}
187-
case Bytecode::Op::Push:
194+
case Bytecode::Op::Push: {
188195
m_stack.emplace_back(*get_imm(bc));
189196
break;
197+
}
190198
case Bytecode::Op::Upper: {
191199
auto result = get_args(bc)[0]->get<std::string>();
192200
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
@@ -443,9 +451,10 @@ class Renderer {
443451
m_stack.emplace_back(std::move(result));
444452
break;
445453
}
446-
case Bytecode::Op::Jump:
454+
case Bytecode::Op::Jump: {
447455
i = bc.args - 1; // -1 due to ++i in loop
448456
break;
457+
}
449458
case Bytecode::Op::ConditionalJump: {
450459
if (!truthy(m_stack.back())) {
451460
i = bc.args - 1; // -1 due to ++i in loop

include/inja/template.hpp

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,9 @@
99

1010
namespace inja {
1111

12-
class Template {
13-
friend class Parser;
14-
friend class Renderer;
15-
12+
struct Template {
1613
std::vector<Bytecode> bytecodes;
1714
std::string content;
18-
19-
public:
20-
Template() {}
21-
Template(const Template& oth): bytecodes(oth.bytecodes), content(oth.content) {}
22-
Template(Template&& oth): bytecodes(std::move(oth.bytecodes)), content(std::move(oth.content)) {}
23-
24-
Template& operator=(const Template& oth) {
25-
bytecodes = oth.bytecodes;
26-
content = oth.content;
27-
return *this;
28-
}
29-
30-
Template& operator=(Template&& oth) {
31-
bytecodes = std::move(oth.bytecodes);
32-
content = std::move(oth.content);
33-
return *this;
34-
}
3515
};
3616

3717
using TemplateStorage = std::map<std::string, Template>;

test/unit-files.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,28 @@
55
using json = nlohmann::json;
66

77

8+
const std::string test_file_directory {"../test/data/"};
9+
810
TEST_CASE("loading") {
9-
inja::Environment env = inja::Environment();
11+
inja::Environment env;
1012
json data;
1113
data["name"] = "Jeff";
1214

1315
SECTION("Files should be loaded") {
14-
CHECK( env.load_file("../test/data/simple.txt") == "Hello {{ name }}." );
16+
CHECK( env.load_file(test_file_directory + "simple.txt") == "Hello {{ name }}." );
1517
}
1618

1719
SECTION("Files should be rendered") {
18-
CHECK( env.render_file("../test/data/simple.txt", data) == "Hello Jeff." );
20+
CHECK( env.render_file(test_file_directory + "simple.txt", data) == "Hello Jeff." );
1921
}
2022

2123
SECTION("File includes should be rendered") {
22-
CHECK( env.render_file("../test/data/include.txt", data) == "Answer: Hello Jeff." );
24+
CHECK( env.render_file(test_file_directory + "include.txt", data) == "Answer: Hello Jeff." );
2325
}
2426
}
2527

2628
TEST_CASE("complete-files") {
27-
inja::Environment env = inja::Environment("../test/data/");
29+
inja::Environment env {test_file_directory};
2830

2931
for (std::string test_name : {"simple-file", "nested", "nested-line", "html"}) {
3032
SECTION(test_name) {
@@ -34,8 +36,8 @@ TEST_CASE("complete-files") {
3436
}
3537

3638
TEST_CASE("global-path") {
37-
inja::Environment env = inja::Environment("../test/data/", "./");
38-
inja::Environment env_result = inja::Environment("./");
39+
inja::Environment env {test_file_directory, "./"};
40+
inja::Environment env_result {"./"};
3941
json data;
4042
data["name"] = "Jeff";
4143

test/unit-renderer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ TEST_CASE("types") {
4343
CHECK( env.render("Hello {{ names.1 }}!", data) == "Hello Seb!" );
4444
CHECK( env.render("Hello {{ brother.name }}!", data) == "Hello Chris!" );
4545
CHECK( env.render("Hello {{ brother.daughter0.name }}!", data) == "Hello Maria!" );
46+
CHECK( env.render("{{ \"{{ no_value }}\" }}", data) == "{{ no_value }}" );
4647

4748
CHECK_THROWS_WITH( env.render("{{unknown}}", data), "[inja.exception.render_error] variable 'unknown' not found" );
4849
}
@@ -215,6 +216,7 @@ TEST_CASE("functions") {
215216
CHECK( env.render("{{ default(nothing, 0) }}", data) == "0" );
216217
CHECK( env.render("{{ default(name, \"nobody\") }}", data) == "Peter" );
217218
CHECK( env.render("{{ default(surname, \"nobody\") }}", data) == "nobody" );
219+
CHECK( env.render("{{ default(surname, \"{{ surname }}\") }}", data) == "{{ surname }}" );
218220
CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable 'lastname' not found" );
219221
}
220222

0 commit comments

Comments
 (0)