Skip to content

Commit 7401668

Browse files
committed
Add for and while loops
for a in 1 10 range do 'a' eval sqrt done while 'a' eval 2 > do 'a-1' eval 'a' sto done Signed-off-by: Vernon Mauery <[email protected]>
1 parent 75d47d6 commit 7401668

13 files changed

+196
-237
lines changed

TODO

+1
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ Ideas for future development
3636
* debug for types
3737
* debug for units
3838
* Multi-processor support for things that can run in parallel
39+
* Timeouts for runaway calculations

src/calculator.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,13 @@ void Calculator::set_var(std::string_view name, const numeric& value)
349349
{
350350
auto& scope = variables.front();
351351
scope[std::string(name)] = value;
352+
lg::debug("set_var('{}', {})\n", name, value);
352353
}
353354

354355
// unset only affects the current scope
355356
void Calculator::unset_var(std::string_view name)
356357
{
358+
lg::debug("unset_var('{}')\n", name);
357359
auto& scope = variables.front();
358360
if (auto p = scope.find(std::string(name)); p != scope.end())
359361
{
@@ -570,7 +572,7 @@ void Calculator::show_stack()
570572
}
571573
else if (auto sym = std::get_if<symbolic>(&v); sym)
572574
{
573-
ui->out("{}'{}'{}\n", row_idx, *sym, it->unit());
575+
ui->out("{}{}{}\n", row_idx, *sym, it->unit());
574576
}
575577
else
576578
{

src/function_library.cpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace
2626
size_t op_names_max_strlen;
2727
std::map<std::string_view, CalcFunction::ptr> operations;
2828
std::vector<std::string_view> function_names;
29+
std::vector<std::string_view> auto_complete_words;
2930
std::map<CalcFunction::ptr, std::string_view> reops;
3031
std::vector<CalcFunction::ptr> user_functions;
3132

@@ -101,6 +102,13 @@ void setup_catalog()
101102
});
102103
std::sort(function_names.begin(), function_names.end());
103104

105+
auto_complete_words = function_names;
106+
auto_complete_words.insert(auto_complete_words.end(),
107+
{"break", "continue", "do", "done", "elif",
108+
"else", "endif", "for", "if", "in", "then",
109+
"while"});
110+
std::sort(auto_complete_words.begin(), auto_complete_words.end());
111+
104112
std::vector<std::tuple<CalcFunction::ptr, std::string_view>> reop_list{};
105113
reops.clear();
106114
for (const auto& [k, v] : operations)
@@ -148,14 +156,14 @@ const std::vector<CalcFunction::ptr>& fn_get_all_user()
148156

149157
std::span<std::string_view> fn_list_all_starts_with(std::string_view start)
150158
{
151-
std::vector<std::string_view>::iterator first = function_names.end();
152-
for (auto iter = function_names.begin(); iter != function_names.end();
153-
iter++)
159+
std::vector<std::string_view>::iterator first = auto_complete_words.end();
160+
for (auto iter = auto_complete_words.begin();
161+
iter != auto_complete_words.end(); iter++)
154162
{
155163
if (iter->starts_with(start))
156164
{
157165
first = iter++;
158-
for (; iter != function_names.end(); iter++)
166+
for (; iter != auto_complete_words.end(); iter++)
159167
{
160168
if (!(iter->starts_with(start)))
161169
{

src/list.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct basic_list
1717
{
1818
using element_type = T;
1919
using default_element_type = typename variant0_or_single<T>::type;
20+
using iterator = std::vector<T>::iterator;
2021

2122
std::vector<T> values;
2223

@@ -42,6 +43,15 @@ struct basic_list
4243
reduce();
4344
}
4445

46+
iterator begin()
47+
{
48+
return values.begin();
49+
}
50+
iterator end()
51+
{
52+
return values.end();
53+
}
54+
4555
void reduce()
4656
{
4757
if constexpr (is_variant_v<T>)

src/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ smrty_lib = static_library(
3838
)
3939

4040
common_src = [
41+
'ctrl_statements.cpp',
4142
'debug.cpp',
4243
'input.cpp',
4344
'numeric.cpp',

src/numeric.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ using list = basic_list<mpx>;
176176
// symbolic uses mpx
177177
#include <symbolic.hpp>
178178
#include <program.hpp>
179+
#include <ctrl_statements.hpp>
179180
// clang-format on
180181

181182
using numeric = std::variant<bool, mpz, mpq, mpf, mpc, list, matrix, time_,

src/parser.cpp

+99-13
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ void print_parser(auto const& context, regex_parser const&, auto& ostream,
1414
} // namespace detail
1515
} // namespace boost::parser
1616

17-
#include <boost/parser/parser.hpp>
1817
#include <cctype>
1918
#include <climits>
19+
#include <ctrl_statements.hpp>
2020
#include <debug.hpp>
2121
#include <fstream>
2222
#include <iostream>
@@ -26,6 +26,9 @@ void print_parser(auto const& context, regex_parser const&, auto& ostream,
2626
#include <regex>
2727
#include <vector>
2828

29+
// this is last
30+
#include <boost/parser/parser.hpp>
31+
2932
namespace bp = ::boost::parser;
3033
using namespace bp::literals;
3134

@@ -219,9 +222,16 @@ bp::rule<class list_r, list> const list_r = "list";
219222
bp::rule<class time, time_parts> const time = "time";
220223
bp::rule<class duration, time_parts> const duration = "duration";
221224

222-
bp::rule<class if_elif, if_elif_statement> const if_elif =
225+
bp::rule<class if_elif, statement::ptr> const if_elif =
223226
"if/then[/elif/else]/endif statement";
224227

228+
bp::rule<class loop_instruction, instruction> const loop_instruction =
229+
"loop body instruction";
230+
bp::rule<class while_loop, statement::ptr> const while_loop =
231+
"while/do/done statement";
232+
bp::rule<class for_loop, statement::ptr> const for_loop =
233+
"for/in/do/done statement";
234+
225235
bp::rule<class program_r, program> const program_r = "program";
226236
bp::rule<class user_input, program> const user_input = "user input";
227237

@@ -401,16 +411,18 @@ auto const parse_if_cond = [](auto& ctx) {
401411
auto& attr = _attr(ctx);
402412
auto& val = _val(ctx);
403413
// print_ctx_types(parse_if_cond);
404-
val.branches.emplace_back(
405-
std::make_tuple(true, simple_program{attr}, program{}));
414+
auto ifstmt = std::make_shared<if_elif_statement>();
415+
ifstmt->set_cond(attr);
416+
val = ifstmt;
406417
};
407418

408419
auto const parse_if_body = [](auto& ctx) {
409420
// parse_if_body: attr = vector<instruction>, val = if_elif_statement
410421
auto& attr = _attr(ctx);
411422
auto& val = _val(ctx);
423+
auto ifstmt = std::dynamic_pointer_cast<if_elif_statement>(val);
412424
// print_ctx_types(parse_if_body);
413-
std::get<program>(val.branches.back()).body = attr;
425+
ifstmt->set_body(attr);
414426
};
415427

416428
auto const parse_else = [](auto& ctx) {
@@ -419,9 +431,53 @@ auto const parse_else = [](auto& ctx) {
419431
auto& val = _val(ctx);
420432
// print_ctx_types(parse_else);
421433
// new branch with an empty condition
422-
val.branches.emplace_back(
423-
std::make_tuple(true, simple_program{}, program{}));
424-
std::get<program>(val.branches.back()).body = attr;
434+
auto ifstmt = std::dynamic_pointer_cast<if_elif_statement>(val);
435+
ifstmt->set_else(attr);
436+
};
437+
438+
auto const parse_while_cond = [](auto& ctx) {
439+
const auto& attr = _attr(ctx);
440+
auto& val = _val(ctx);
441+
// print_ctx_types(parse_while_cond);
442+
auto whl = std::make_shared<while_statement>();
443+
whl->cond = attr;
444+
val = whl;
445+
};
446+
447+
auto const parse_loop_body = [](auto& ctx) {
448+
const auto& attr = _attr(ctx);
449+
auto& val = _val(ctx);
450+
// print_ctx_types(parse_loop_body);
451+
if (auto whl = std::dynamic_pointer_cast<while_statement>(val); whl)
452+
{
453+
whl->set_body(attr);
454+
val = whl;
455+
}
456+
else if (auto fl = std::dynamic_pointer_cast<for_statement>(val); fl)
457+
{
458+
fl->set_body(attr);
459+
val = fl;
460+
}
461+
};
462+
463+
auto const parse_for_var = [](auto& ctx) {
464+
const auto& attr = _attr(ctx);
465+
auto& val = _val(ctx);
466+
// print_ctx_types(parse_for_var);
467+
auto fl = std::make_shared<for_statement>();
468+
// fl->var_name = std::get<std::string>((*attr).left);
469+
fl->set_var(attr);
470+
val = fl;
471+
};
472+
473+
auto const parse_for_cond = [](auto& ctx) {
474+
const auto& attr = _attr(ctx);
475+
auto& val = _val(ctx);
476+
// print_ctx_types(parse_for_cond);
477+
// parse_for_cond: attr = vector<simple_instruction>, val = for_statement
478+
auto fl = std::dynamic_pointer_cast<for_statement>(val);
479+
fl->set_setup(attr);
480+
val = fl;
425481
};
426482

427483
auto const parse_real = [](auto& ctx) {
@@ -654,6 +710,21 @@ auto const save_time_suffix = [](auto& ctx) {
654710
val.suffix = attr;
655711
};
656712

713+
auto const parse_keyword = [](auto& ctx) {
714+
const auto& attr = _attr(ctx);
715+
auto& val = _val(ctx);
716+
print_ctx_types(parse_keyword);
717+
keyword k{attr};
718+
val = simple_instruction{k};
719+
};
720+
721+
auto const passthru = [](auto& ctx) {
722+
const auto& attr = _attr(ctx);
723+
auto& val = _val(ctx);
724+
print_ctx_types(passthru);
725+
val = attr;
726+
};
727+
657728
auto const set_binary = [](auto& ctx) {
658729
auto& val = _val(ctx);
659730
print_ctx_val_type(set_binary);
@@ -773,10 +844,10 @@ auto re_fn_def = bp::regex()[parse_regulars];
773844

774845
auto const simple_instruction_r_def =
775846
(boolean | re_fn | function | time | duration | number_r | matrix_r |
776-
list_r | program_r | operators)[parse_simple_instruction];
847+
list_r | symbolic_r | program_r | operators)[parse_simple_instruction];
777848

778849
auto const instruction_r_def =
779-
(if_elif | simple_instruction_r | symbolic_r)[parse_instruction];
850+
(if_elif | while_loop | for_loop | simple_instruction_r)[parse_instruction];
780851

781852
auto const if_elif_def =
782853
"if"_l > (+simple_instruction_r)[parse_if_cond] > "then"_l >
@@ -785,6 +856,19 @@ auto const if_elif_def =
785856
"then"_l > (+(instruction_r - if_sub_words))[parse_if_body]) >
786857
-("else"_l > (+(instruction_r - if_sub_words))[parse_else]) > "endif"_l;
787858

859+
auto const loop_instruction_def =
860+
(bp::string("break") | bp::string("continue"))[parse_keyword] |
861+
instruction_r[passthru];
862+
863+
auto const while_loop_def = "while"_l >
864+
(+simple_instruction_r)[parse_while_cond] > "do"_l >
865+
(+loop_instruction)[parse_loop_body] > "done"_l;
866+
867+
auto const for_loop_def = "for"_l > bp::lexeme[variable[parse_for_var]] >
868+
"in"_l > (+simple_instruction_r)[parse_for_cond] >
869+
"do"_l > (+loop_instruction)[parse_loop_body] >
870+
"done"_l;
871+
788872
auto const program_r_def = "$("_l > (*instruction_r)[parse_standalone_program] >
789873
")"_l;
790874

@@ -1068,9 +1152,11 @@ auto const symbolic_r_def = "'"_l[set_no_commas] >
10681152

10691153
BOOST_PARSER_DEFINE_RULES(uinteger, integer, ufloating, floating, rati0nal,
10701154
c0mplex, number_r, hex_int, oct_int, bin_int,
1071-
matrix_r, list_r, time, duration, if_elif,
1072-
simple_instruction_r, instruction_r, program_r, re_fn,
1073-
function, operators, user_input);
1155+
matrix_r, list_r, time, duration, if_elif, while_loop,
1156+
for_loop, loop_instruction, simple_instruction_r,
1157+
instruction_r, program_r, re_fn, function, operators,
1158+
user_input);
1159+
10741160
BOOST_PARSER_DEFINE_RULES(variable, paren_expr, paren_fn, paren_fn_call,
10751161
expr_atomic, factorial, expon, negation, multdiv,
10761162
addsub, equation, symbolic_r);

src/parser_main.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Copyright © 2024 Vernon Mauery; All rights reserved.
44
SPDX-License-Identifier: BSD-3-Clause
55
*/
66

7+
#include <calculator.hpp>
78
#include <input.hpp>
89
#include <numeric.hpp>
910
#include <optional>
@@ -130,6 +131,14 @@ std::string_view fn_get_name(CalcFunction::ptr p)
130131
return "<unknown-function>";
131132
}
132133

134+
// for-loops need to directly acces calculator, so need to stub it out here
135+
Calculator::Calculator()
136+
{
137+
}
138+
void Calculator::set_var(std::string_view, const numeric&)
139+
{
140+
}
141+
133142
} // namespace smrty
134143

135144
void setup_regex_ops()

src/parser_parts.hpp

+1-12
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,15 @@ SPDX-License-Identifier: BSD-3-Clause
88

99
#include <format>
1010
#include <function_library.hpp>
11+
#include <numeric.hpp>
1112
#include <parser.hpp>
12-
#include <regex>
1313
#include <std_container_format.hpp>
1414
#include <string>
1515
#include <vector>
1616

1717
namespace smrty
1818
{
1919

20-
constexpr auto invalid_function = nullptr;
21-
22-
enum class symbolic_op
23-
{
24-
none,
25-
paren,
26-
prefix,
27-
infix,
28-
postfix,
29-
};
30-
3120
struct single_number_parts
3221
{
3322
single_number_parts() :

0 commit comments

Comments
 (0)