Skip to content

Commit 93ac7f7

Browse files
authored
Merge pull request #7 from rusini/alex
2 parents 0add65b + 5cae14b commit 93ac7f7

26 files changed

+240
-484
lines changed

AUTHORS

Lines changed: 0 additions & 3 deletions
This file was deleted.

AUTHORS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Alexey Protasov (AKA Alex or rusini)
2+
info@manool.org
3+
https://manool.org

GNUmakefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ libdecnumber-objs = $(patsubst %,build/obj/libdecnumber/%.o, \
8989
decimal128 \
9090
) # end
9191

92-
build/mnlexec : $(manool-objs) $(libdecnumber-objs) | build/lib/manool.org.18/std/0.5/all.mnl ; @mkdir -p $(dir $@)
92+
build/mnlexec : $(manool-objs) $(libdecnumber-objs) | build/lib/manool.org.18/std/0.6/all.mnl ; @mkdir -p $(dir $@)
9393
$(strip $(CXX) -rdynamic -o $@ $(LDFLAGS) $^ $(LDLIBS))
9494
@printf '\33[0m\33[1m*** Success! To run MANOOL try: ./mnl \33[4mmanool-source-file\33[24m [\33[4margument\33[24m...] ***\33[0m\n'
9595

@@ -102,7 +102,7 @@ plugins = $(patsubst %,build/lib/manool.org.18/std/_%.mnl-plugin, \
102102
threads \
103103
misc \
104104
) # end
105-
build/lib/manool.org.18/std/0.5/all.mnl : lib-0.5-all.mnl | $(plugins) ; @mkdir -p $(dir $@)
105+
build/lib/manool.org.18/std/0.6/all.mnl : lib-0.6-all.mnl | $(plugins) ; @mkdir -p $(dir $@)
106106
cp $< $@
107107
$(plugins) : build/lib/manool.org.18/std/_%.mnl-plugin : lib-%-main.cc ; @mkdir -p $(dir $@)
108108
$(strip $(CXX) -shared $(LDFLAGS_SO) -o $@ -MMD -MP $(CXXFLAGS) $(CPPFLAGS) $(mnl_config) $(LDFLAGS) $< $(LDLIBS))
@@ -129,9 +129,9 @@ includes = \
129129
# end
130130
install : all
131131
rm -rf $(PREFIX)/bin/mnlexec $(PREFIX)/lib/manool $(PREFIX)/include/manool
132-
mkdir -p $(PREFIX)/bin $(PREFIX)/lib/manool/manool.org.18/std/0.5 $(PREFIX)/include/manool
132+
mkdir -p $(PREFIX)/bin $(PREFIX)/lib/manool/manool.org.18/std/0.6 $(PREFIX)/include/manool
133133
cp build/mnlexec $(PREFIX)/bin
134-
cp build/lib/manool.org.18/std/0.5/all.mnl $(PREFIX)/lib/manool/manool.org.18/std/0.5
134+
cp build/lib/manool.org.18/std/0.6/all.mnl $(PREFIX)/lib/manool/manool.org.18/std/0.6
135135
cp $(plugins) $(PREFIX)/lib/manool/manool.org.18/std
136136
cp $(includes) $(PREFIX)/include/manool
137137
.PHONY : install

INSTALL.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ General Instructions
77
Try, e.g.:
88

99
make
10-
./mnl <(echo $'{{extern "manool.org.18/std/0.5/all"} in Out.WriteLine["Hello, world!"]}')
10+
./mnl <(echo $'{{extern "manool.org.18/std/0.6/all"} in Out.WriteLine["Hello, world!"]}')
1111

1212
Note that there is no need to run `./configure` (though, it's harmless), since the set of supported host/target platforms is more homogeneous than it used to be
1313
for GNU tools, and thus all platform-specific tuning can be done in a simpler way (that is, during actual building). In theory, the source file `config.tcc` is
@@ -17,7 +17,7 @@ To run MANOOL from within a different directory, point the environment variable
1717
`mnlexec` as in the following example:
1818

1919
MNL_PATH=<working-tree directory>/build/lib <working-tree directory>/build/mnlexec \
20-
<(echo $'{{extern "manool.org.18/std/0.5/all"} in Out.WriteLine["Hello, world!"]}')
20+
<(echo $'{{extern "manool.org.18/std/0.6/all"} in Out.WriteLine["Hello, world!"]}')
2121

2222
The section Confirmed Builds provides more specific instructions together with recommended compilation options for 23 combinations of OSes/ISAs/ABIs/compilers.
2323

@@ -94,7 +94,7 @@ To install MANOOL after building, try, e.g. (also read about the `PREFIX` makefi
9494
To run installed MANOOL, point the environment variable `MNL_PATH` to the installed-library directory, e.g.:
9595

9696
MNL_PATH=/usr/local/lib/manool mnlexec \
97-
<(echo $'{{extern "manool.org.18/std/0.5/all"} in Out.WriteLine["Hello, world!"]}')
97+
<(echo $'{{extern "manool.org.18/std/0.6/all"} in Out.WriteLine["Hello, world!"]}')
9898

9999
To get the `mnlexec` invocation synopsis and a short description of all recognized environment variables, just run it without arguments: `mnlexec`.
100100

@@ -104,7 +104,7 @@ environment):
104104

105105
cat >hello && chmod +x hello
106106
#!/usr/bin/env mnlexec
107-
{{extern "manool.org.18/std/0.5/all"} in Out.WriteLine["Hello, world!"]}
107+
{{extern "manool.org.18/std/0.6/all"} in Out.WriteLine["Hello, world!"]}
108108
<Control-D>
109109
./hello
110110

@@ -181,7 +181,7 @@ Confirmed Builds
181181

182182
***
183183

184-
+ openSUSE Leap 15.1, x86-64, x86-64/lp64, g++
184+
+ openSUSE Leap 15.2, x86-64, x86-64/lp64, g++
185185

186186
sudo zypper install gcc-c++ make
187187
make
@@ -198,15 +198,15 @@ Confirmed Builds
198198

199199
+ CentOS 6, x86-64, x86-64/lp64, g++
200200

201-
sudo yum install centos-release-scl && sudo yum install devtoolset-8-gcc-c++
202-
make SCL='scl enable devtoolset-8 --'
201+
sudo yum install centos-release-scl && sudo yum install devtoolset-9-gcc-c++
202+
make SCL='scl enable devtoolset-9 --'
203203

204204
***
205205

206206
+ CentOS 7, x86-64, x86-64/lp64, g++
207207

208-
sudo yum install centos-release-scl && sudo yum install devtoolset-8-gcc-c++
209-
make SCL='scl enable devtoolset-8 --'
208+
sudo yum install centos-release-scl && sudo yum install devtoolset-9-gcc-c++
209+
make SCL='scl enable devtoolset-9 --'
210210

211211
+ CentOS 7, x86-64, x86-64/lp64, clang++
212212

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
1-
<img alt="MANOOL Logo" src="https://manool.org/MANOOL-Logo.png" width="64" height="64"> MANOOL v0.5.0
1+
<img alt="MANOOL Logo" src="https://manool.org/MANOOL-Logo.png" width="64" height="64"> MANOOL v0.6.0
22
=====================================================================================================
33

4-
MANOOL is a programming language with the same purpose as Python, Ruby, PHP, Common Lisp, or Scheme, but it is designed with one central idea in mind:
5-
* to maximize the *expressive power / implementation complexity* ratio.
4+
**MANOOL is meant to make exploratory programming safer and faster.**
65

7-
The author's implementation fits in only 10 KLOC in C++, yet it exhibits competitive run-time performance.
6+
Some programming tasks are common and predictable from the project management perspective, but often, even enterprise information systems (especially in the
7+
area of startups) involve some innovation and exploratory programming. Imagine you have such task at hand. Whenever this happens you have two options:
8+
1. use an *implementation-level* programming language, such as C, C++, Java, or maybe Rust (if you want to try a more recent approach) or
9+
2. use a language more suitable for *throw-away* programming, such as PHP, Python, Ruby, JavaScript, or even Scheme.
810

9-
**For a complete project overview**, please refer to [Introduction to MANOOL](https://manool.org/specification/introduction-to-manool).
11+
In the former case, you eventually get stuck with your coding -- trying to conceive some poorly understood algorithms, deciding which data types to use and how
12+
to get around seemingly arbitrary constraints for composite data types, devising resource management policies, and dealing with confusing program logic.
1013

11-
"**MA**NOOL is *Not* an Object-Oriented Language!"
14+
Then you resort to the second option, in which case you also have to conceive poorly understood algorithms, deal with confusing program logic, and occasionally
15+
think about how to circumvent composite data type constraints, but most probably you end up familiarized yourself with the problem domain and come to a working
16+
prototype.
17+
18+
You show your solution (which mostly looks nice) to the managers, and suddenly they react: "OK, let's clear up the bugs; tomorrow we deploy it in production!".
19+
Then disaster falls on you; after some time of production use, it turns out that
20+
* your code is not scalable to a grown user base and hence larger workload, or the solution is simply slow according to your end users,
21+
* your code has mysterious and hard to localize bugs, and of course
22+
* the program logic itself still looks confusing and complex.
23+
24+
This happens because paying attention to those details would imply undue cognitive burden at the early stage of development. And unlike your managers you
25+
already knew that: a major rewrite is unavoidable, now in a "real" implementation-level language -- does this sound familiar?
26+
27+
While MANOOL is a general-purpose programming language, it is specifically designed to solve the above problem. It may also help you to come to a working
28+
prototype faster and then gradually refactor your code up to a production-quality state instead of rewriting the code entirely from scratch.

core-misc.cc

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,32 @@
1616
# include "config.tcc"
1717
# include "mnl-aux-core.tcc"
1818

19+
# include <time.h> // clock_gettime
1920
# include <cstdio> // sprintf, stderr, fprintf, fputs, fflush
20-
# include <ctime> // time
2121

2222
namespace MNL_AUX_UUID { using namespace aux;
2323
namespace aux {
24-
using std::_Exit; // <cstdlib>
24+
using std::_Exit; using std::srand; // <cstdlib>
2525
using std::sprintf; using std::fprintf; using std::fputs; using std::fflush; // <cstdio>
26-
using std::time; // <time>
2726
}
2827

2928
// Translation Infrastructure //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3029
MNL_IF_WITH_MT(thread_local) decltype(symtab) pub::symtab;
3130

31+
namespace aux { namespace { struct stub {
32+
MNL_INLINE static val execute(bool) { MNL_UNREACHABLE(); }
33+
MNL_INLINE static void exec_in(val &&) { MNL_UNREACHABLE(); }
34+
MNL_INLINE static val exec_out() { MNL_UNREACHABLE(); }
35+
MNL_INLINE static bool is_rvalue() { return false; }
36+
MNL_INLINE static bool is_lvalue() { return false; }
37+
MNL_INLINE static code compile(code &&, const form &, const loc &_loc) { err_compile("invalid form", _loc); }
38+
}; }}
3239
code pub::compile(const form &form, const loc &_loc) { return // *** The Compiler Core Dispatcher! ***
3340
test<sym>(form) && symtab[cast<const sym &>(form)] ?
3441
symtab[cast<const sym &>(form)] :
35-
test<sym>(form) && ((const string &)cast<const sym &>(form))[0] >= 'a' && ((const string &)cast<const sym &>(form))[0] <= 'z' ?
36-
(err_compile("unbound keyword (nested in this context)", form._loc(_loc)), code{}) :
42+
test<sym>(form) && (((const string &)cast<const sym &>(form))[0] >= 'a' && ((const string &)cast<const sym &>(form))[0] <= 'z' ||
43+
((const string &)cast<const sym &>(form))[0] == '_' || ((const string &)cast<const sym &>(form))[0] == '`') ?
44+
MNL_AUX_INIT((code)stub{}) :
3745
test<long long>(form) || test<string>(form) || test<sym>(form) ?
3846
[&]()->code{ code make_lit(const val &); return make_lit(form); }() : // actually from MANOOL API
3947
form.is_list() && !form.empty() ?
@@ -107,8 +115,12 @@ namespace MNL_AUX_UUID { using namespace aux;
107115
return !MNL_LIKELY(argv[0].rep.tag() == 0x7FF8u) || argv[0].rep.dat<void *>() != rep.dat<void *>();
108116
case 3: // Order
109117
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
110-
if (MNL_UNLIKELY(argv[0].rep.tag() != 0x7FF8u) || MNL_UNLIKELY(argv[0].rep.dat<void *>() != rep.dat<void *>())) MNL_ERR(MNL_SYM("TypeMismatch"));
111-
return 0;
118+
{ auto mask = MNL_AUX_RAND(uintptr_t);
119+
int res = default_order(argv[0]);
120+
return MNL_UNLIKELY(res) ? res :
121+
((reinterpret_cast<uintptr_t>(rep.dat<void *>()) ^ mask) < (reinterpret_cast<uintptr_t>(argv[0].rep.dat<void *>()) ^ mask)) -
122+
((reinterpret_cast<uintptr_t>(argv[0].rep.dat<void *>()) ^ mask) < (reinterpret_cast<uintptr_t>(rep.dat<void *>()) ^ mask));
123+
}
112124
case 4: // Clone
113125
if (MNL_UNLIKELY(argc != 0)) MNL_ERR(MNL_SYM("InvalidInvocation"));
114126
return move(*this);
@@ -162,11 +174,19 @@ namespace MNL_AUX_UUID { using namespace aux;
162174
record_descr::record_descr(initializer_list<const char *> il): record_descr([=]()->set<sym>{
163175
set<sym> res; for (auto el: il) res.insert(el); return res;
164176
}()) {}
177+
int pub::order(const record_descr &lhs, const record_descr &rhs) noexcept {
178+
auto mask = MNL_AUX_RAND(uintptr_t);
179+
return
180+
((reinterpret_cast<uintptr_t>(&*lhs.rep) ^ mask) < (reinterpret_cast<uintptr_t>(&*rhs.rep) ^ mask)) -
181+
((reinterpret_cast<uintptr_t>(&*rhs.rep) ^ mask) < (reinterpret_cast<uintptr_t>(&*lhs.rep) ^ mask));
182+
}
165183

166184
decltype(record_descr::store) record_descr::store;
167185
MNL_IF_WITH_MT(decltype(record_descr::mutex) record_descr::mutex;)
168186

169187
// Seed Legacy Random Number Generator /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
170-
namespace aux { namespace { MNL_PRIORITY(1000) struct { int _ = (srand(time({})), 0); } _srand; }}
188+
namespace aux { namespace { MNL_PRIORITY(1000) class { int _ = []()->int{
189+
struct ::timespec ts; ::clock_gettime(CLOCK_REALTIME, &ts); return srand(ts.tv_sec ^ (unsigned)ts.tv_nsec / 1000), 0;
190+
}(); } _srand; }}
171191

172192
} // namespace MNL_AUX_UUID

core-ops.cc

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ namespace aux {
436436
return !test<>(argv[1]);
437437
case sym::op_order:
438438
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
439-
if (MNL_UNLIKELY(!test<>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
439+
if (MNL_UNLIKELY(!test<>(argv[1]))) return argv[0].default_order(argv[1]);
440440
return 0;
441441
case sym::op_clone: case sym::op_deep_clone:
442442
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -512,7 +512,7 @@ namespace aux {
512512
return cast<long long>(argv[0]) >= cast<long long>(argv[1]);
513513
case sym::op_order:
514514
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
515-
if (MNL_UNLIKELY(!test<long long>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
515+
if (MNL_UNLIKELY(!test<long long>(argv[1]))) return argv[0].default_order(argv[1]);
516516
return (cast<long long>(argv[0]) > cast<long long>(argv[1])) - (cast<long long>(argv[0]) < cast<long long>(argv[1]));
517517
case sym::op_abs:
518518
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -580,7 +580,7 @@ namespace aux {
580580
return cast<DAT>(argv[0]) >= cast<DAT>(argv[1]); \
581581
case sym::op_order: \
582582
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation")); \
583-
if (MNL_UNLIKELY(!test<DAT>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch")); \
583+
if (MNL_UNLIKELY(!test<DAT>(argv[1]))) return argv[0].default_order(argv[1]); \
584584
return signbit(cast<DAT>(argv[0])) ^ signbit(cast<DAT>(argv[1])) ? signbit(cast<DAT>(argv[1])) - signbit(cast<DAT>(argv[0])) : \
585585
cast<DAT>(argv[0]) < cast<DAT>(argv[1]) ? -1 : cast<DAT>(argv[0]) != cast<DAT>(argv[1]); \
586586
case sym::op_abs: \
@@ -724,7 +724,7 @@ namespace aux {
724724
return !MNL_LIKELY(test<sym>(argv[1])) || cast<const sym &>(argv[0]) != cast<const sym &>(argv[1]);
725725
case sym::op_order:
726726
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
727-
if (MNL_UNLIKELY(!test<sym>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
727+
if (MNL_UNLIKELY(!test<sym>(argv[1]))) return argv[0].default_order(argv[1]);
728728
return (cast<sym>(argv[0]) > cast<sym>(argv[1])) - (cast<sym>(argv[0]) < cast<sym>(argv[1]));
729729
case sym::op_apply:
730730
return cast<const sym &>(argv[0])(argc - 1, argv + 1, argv_out + !!argv_out);
@@ -746,7 +746,7 @@ namespace aux {
746746
return argv[1].rep.tag() != 0x7FFEu;
747747
case sym::op_order:
748748
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
749-
if (MNL_UNLIKELY(!test<bool>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
749+
if (MNL_UNLIKELY(!test<bool>(argv[1]))) return argv[0].default_order(argv[1]);
750750
return +-cast<bool>(argv[1]);
751751
case sym::op_or:
752752
case sym::op_xor:
@@ -778,7 +778,7 @@ namespace aux {
778778
return argv[1].rep.tag() != 0x7FFFu;
779779
case sym::op_order:
780780
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
781-
if (MNL_UNLIKELY(!test<bool>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
781+
if (MNL_UNLIKELY(!test<bool>(argv[1]))) return argv[0].default_order(argv[1]);
782782
return +!cast<bool>(argv[1]);
783783
case sym::op_and:
784784
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -854,7 +854,7 @@ namespace aux {
854854
return cast<unsigned>(argv[0]) >= cast<unsigned>(argv[1]);
855855
case sym::op_order:
856856
if (MNL_UNLIKELY(argc != 2)) MNL_ERR(MNL_SYM("InvalidInvocation"));
857-
if (MNL_UNLIKELY(!test<unsigned>(argv[1]))) MNL_ERR(MNL_SYM("TypeMismatch"));
857+
if (MNL_UNLIKELY(!test<unsigned>(argv[1]))) return argv[0].default_order(argv[1]);
858858
return (cast<unsigned>(argv[0]) > cast<unsigned>(argv[1])) - (cast<unsigned>(argv[0]) < cast<unsigned>(argv[1]));
859859
case sym::op_abs:
860860
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
@@ -1225,7 +1225,7 @@ namespace aux {
12251225
return !MNL_LIKELY(test<string>(argv[0])) || (MNL_IF_WITH_IDENT_OPT(&dat != &cast<const string &>(argv[0]) &&) dat != cast<const string &>(argv[0]));
12261226
case sym::op_order:
12271227
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1228-
if (MNL_UNLIKELY(!test<string>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
1228+
if (MNL_UNLIKELY(!test<string>(argv[0]))) return self.default_order(argv[0]);
12291229
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const string &>(argv[0])) return 0;)
12301230
for (auto lhs = dat.cbegin(), rhs = cast<const string &>(argv[0]).begin();; ++lhs, ++rhs) {
12311231
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const string &>(argv[0]).end());
@@ -1416,7 +1416,7 @@ namespace aux {
14161416
}
14171417
case sym::op_order:
14181418
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1419-
if (MNL_UNLIKELY(!test<vector<val>>(argv[0]))) MNL_ERR(MNL_SYM("TypeMismatch"));
1419+
if (MNL_UNLIKELY(!test<vector<val>>(argv[0]))) return self.default_order(argv[0]);
14201420
MNL_IF_WITH_IDENT_OPT(if (&dat == &cast<const vector<val> &>(argv[0])) return 0;)
14211421
for (auto lhs = dat.cbegin(), rhs = cast<const vector<val> &>(argv[0]).begin();; ++lhs, ++rhs) {
14221422
if (MNL_UNLIKELY(lhs == dat.cend())) return -(rhs != cast<const vector<val> &>(argv[0]).end());
@@ -1554,8 +1554,9 @@ namespace aux {
15541554
return false;
15551555
case sym::op_order:
15561556
if (MNL_UNLIKELY(argc != 1)) MNL_ERR(MNL_SYM("InvalidInvocation"));
1557-
if (MNL_UNLIKELY(!test<_record>(argv[0])) || MNL_UNLIKELY(descr != cast<const _record &>(argv[0]).descr)) MNL_ERR(MNL_SYM("TypeMismatch"));
1557+
if (MNL_UNLIKELY(!test<_record>(argv[0]))) return self.default_order(argv[0]);
15581558
MNL_IF_WITH_IDENT_OPT(if (this == &cast<const _record &>(argv[0])) return 0;)
1559+
{ int res = order(descr, cast<const _record &>(argv[0]).descr); if (MNL_UNLIKELY(res)) return res; }
15591560
for (auto lhs = begin(const_cast<const _record *>(this)->items), rhs = begin(cast<const _record &>(argv[0]).items); lhs != end(items); ++lhs, ++rhs)
15601561
{ auto res = safe_cast<long long>(op(args<2>{*lhs, *rhs})); if (MNL_UNLIKELY(res)) return res; }
15611562
return 0;

0 commit comments

Comments
 (0)