about summary refs log tree commit diff stats
path: root/archive/1.vm/020run.cc
blob: aa4513e4bb05040a3a6f091f264ea2bcb8021422 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings.  \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
.    ds -- \(*W-
.    ds PI pi
.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
.    ds L" ""
.    ds R" ""
.    ds C` ""
.    ds C' ""
'br\}
.el\{\
.    ds -- \|\(em\|
.    ds PI \(*p
.    ds L" ``
.    ds R" ''
.    ds C`
.    ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el       .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD.  Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.if !\nF .nr F 0
.if \nF>0 \{\
.    de IX
.    tm Index:\\$1\t\\n%\t"\\$2"
..
.    if !\nF==2 \{\
.        nr % 0
.        nr F 2
.    \}
.\}
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
.    \" fudge factors for nroff and troff
.if n \{\
.    ds #H 0
.    ds #V .8m
.    ds #F .3m
.    ds #[ \f1
.    ds #] \fP
.\}
.if t \{\
.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
.    ds #V .6m
.    ds #F 0
.    ds #[ \&
.    ds #] \&
.\}
.    \" simple accents for nroff and troff
.if n \{\
.    ds ' \&
.    ds ` \&
.    ds ^ \&
.    ds , \&
.    ds ~ ~
.    ds /
.\}
.if t \{\
.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
.    \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
.    \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
.    \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
.    ds : e
.    ds 8 ss
.    ds o a
.    ds d- d\h'-1'\(ga
.    ds D- D\h'-1'\(hy
.    ds th \o'bp'
.    ds Th \o'LP'
.    ds ae ae
.    ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "RIFLE 1"
.TH RIFLE 1 "rifle-1.9.0" "2018-01-25" "rifle manual"
.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
rifle \- ranger's file opener
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
\&\fBrifle\fR [\fB\-\-help\fR] [\fB\-f\fR \fI\s-1FLAGS\s0\fR] [\fB\-l\fR] [\fB\-p\fR \fI\s-1KEYWORD\s0\fR]
[\fB\-w\fR \fI\s-1PROGRAM\s0\fR] [\fB\-c\fR \fI\s-1CONFIG_FILE\s0\fR] \fIfiles\fR
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
rifle is a powerful file executor that allows for complex file type checking,
written to meet the needs of the file manager \fIranger\fR.  rifle's strength lies
in automatically determining file types, depending on which programs are
installed on the system, even without any user interaction.
.SH "OPTIONS"
.IX Header "OPTIONS"
.IP "\fB\-f\fR \fI\s-1FLAGS\s0\fR" 14
.IX Item "-f FLAGS"
Specify flags for opening the files.  Flags are letters that changes how the
program is executed.  Any combination of flags will work.  Writing uppercase
flags will negate the effect of all previously used lowercase flags of the same
letter.
.Sp
Table of all flags:
 f   fork program to background
 r   run program as root, using sudo
 t   run program in a separate terminal, as specified by \f(CW$TERMCMD\fR
.IP "\fB\-l\fR" 14
.IX Item "-l"
List all possible ways to open the specified files.  Each line will contain information in the format of \fIid:label:flags:command\fR. \fIid\fR is the identification number. \fIlabel\fR is an arbitrary string that was specified for this command, \fIflags\fR are the flags that are used by default, and \fIcommand\fR is the command that is going to be executed.
.IP "\fB\-p\fR \fI\s-1KEYWORD\s0\fR" 14
.IX Item "-p KEYWORD"
Pick a method to open the files.
.Sp
\&\fI\s-1KEYWORD\s0\fR is either the \s-1ID\s0 number listed by \f(CW\*(C`rifle \-l\*(C'\fR or a string that matches a label in the configuration file.
.IP "\fB\-w\fR \fI\s-1PROGRAM\s0\fR" 14
.IX Item "-w PROGRAM"
Open the files with the program \fI\s-1PROGRAM\s0\fR
.IP "\fB\-c\fR \fI\s-1CONFIG_FILE\s0\fR" 14
.IX Item "-c CONFIG_FILE"
Read configuration from \fI\s-1CONFIG_FILE\s0\fR, instead of the default.
.IP "\fB\-h\fR, \fB\-\-help\fR" 14
.IX Item "-h, --help"
Print a list of options and exit.
.SH "FILES"
.IX Header "FILES"
rifle shares configuration files with ranger, though ranger is not required in
order to use rifle. The default configuration file \fIrifle.conf\fR is expected
to be at \fI~/.config/ranger/rifle.conf\fR. However, this can be overridden with
the \fB\-c\fR option.
.PP
This file specifies patterns for determining the commands to open files with.
The syntax is described in the comments of the default \fIrifle.conf\fR that ships
with ranger.  To obtain it, you need to run: \f(CW\*(C`ranger \-\-copy\-config=rifle\*(C'\fR
.SH "ENVIRONMENT"
.IX Header "ENVIRONMENT"
.IP "\s-1VISUAL\s0" 8
.IX Item "VISUAL"
Determines which editor to use for editing files.
.IP "\s-1EDITOR\s0" 8
.IX Item "EDITOR"
Determines which editor to use for editing files if \s-1VISUAL\s0 is undefined or
empty (in the default \fIrifle.conf\fR). If both are undefined or empty, \*(L"vim\*(R" is
used instead.
.IP "\s-1PAGER\s0" 8
.IX Item "PAGER"
Determines which pager to use for displaying files (in the default \fIrifle.conf\fR).
.IP "\s-1TERMCMD\s0" 8
.IX Item "TERMCMD"
Determines the terminal emulator command for use with the \fIt\fR flag.  It is required that the value is the path to an executable file which accepts the \*(L"\-e \s-1COMMAND\*(R"\s0 argument.
.IP "\s-1XDG_CONFIG_HOME\s0" 8
.IX Item "XDG_CONFIG_HOME"
Specifies the directory for configuration files. Defaults to \fI\f(CI$HOME\fI/.config\fR.
.SH "EXAMPLES"
.IX Header "EXAMPLES"
List all the different methods:
.PP
.Vb 4
\& $ rifle \-l helloworld.py
\& 0:editor::"$EDITOR" \-\- "$@"
\& 1:pager::"$PAGER" \-\- "$@"
\& 2:::python \-\- "$1"
.Ve
.PP
Display its content by opening it with \*(L"cat\*(R":
.PP
.Vb 2
\& $ rifle \-w cat helloworld.py
\& print("Hello World!")
.Ve
.PP
Run it by picking the method 2, which calls 'python \*(-- \*(L"$1\*(R"':
.PP
.Vb 2
\& $ rifle \-p 2 helloworld.py
\& Hello World!
.Ve
.PP
Display the file in a pager inside a new terminal, run as root:
.PP
.Vb 1
\& $ rifle \-p 1 \-f tr helloworld.py
.Ve
class="n">at(i))); } // instructions below will write to 'products' vector<vector<double> > products; //: This will be a large switch that later layers will often insert cases //: into. Never call 'continue' within it. Instead, we'll explicitly //: control which of the following stages after the switch we run for each //: instruction. bool write_products = true; bool fall_through_to_next_instruction = true; switch (current_instruction().operation) { // Primitive Recipe Implementations case COPY: { copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin())); break; } // End Primitive Recipe Implementations default: { raise << "not a primitive op: " << current_instruction().operation << '\n' << end(); } } //: used by a later layer if (write_products) { if (SIZE(products) < SIZE(current_instruction().products)) { raise << SIZE(products) << " vs " << SIZE(current_instruction().products) << ": failed to write to all products in '" << to_original_string(current_instruction()) << "'\n" << end(); } else { for (int i = 0; i < SIZE(current_instruction().products); ++i) { // Writing Instruction Product(i) write_memory(current_instruction().products.at(i), products.at(i)); } } } // End Running One Instruction if (fall_through_to_next_instruction) ++current_step_index(); } stop_running_current_routine:; } //: Helpers for managing trace depths //: //: We're going to use trace depths primarily to segment code running at //: different frames of the call stack. This will make it easy for the trace //: browser to collapse over entire calls. //: //: The entire map of possible depths is as follows: //: //: Errors will be depth 0. //: Mu 'applications' will be able to use depths 1-99 as they like. //: Primitive statements will occupy 100 and up to Max_depth, organized by //: stack frames. :(before "End Globals") extern const int Initial_callstack_depth = 100; int Callstack_depth = Initial_callstack_depth; :(before "End Reset") Callstack_depth = Initial_callstack_depth; //: Other helpers for the VM. :(code) //: hook replaced in a later layer bool should_continue_running(const routine* current_routine) { assert(current_routine == Current_routine); // argument passed in just to make caller readable above return !Current_routine->completed(); } bool should_copy_ingredients() { // End should_copy_ingredients Special-cases return true; } bool is_mu_scalar(reagent/*copy*/ r) { return is_mu_scalar(r.type); } bool is_mu_scalar(const type_tree* type) { if (!type) return false; if (is_mu_address(type)) return false; if (!type->atom) return false; if (is_literal(type)) return type->name != "literal-string"; return size_of(type) == 1; } bool is_mu_address(reagent/*copy*/ r) { // End Preprocess is_mu_address(reagent r) return is_mu_address(r.type); } bool is_mu_address(const type_tree* type) { if (!type) return false; if (is_literal(type)) return false; if (type->atom) return false; if (!type->left->atom) { raise << "invalid type " << to_string(type) << '\n' << end(); return false; } return type->left->value == Address_type_ordinal; } //: Some helpers. //: Important that they return references into the current routine. //: hook replaced in a later layer int& current_step_index() { return Current_routine->running_step_index; } //: hook replaced in a later layer recipe_ordinal currently_running_recipe() { return Current_routine->running_recipe; } //: hook replaced in a later layer const string& current_recipe_name() { return get(Recipe, Current_routine->running_recipe).name; } //: hook replaced in a later layer const recipe& current_recipe() { return get(Recipe, Current_routine->running_recipe); } //: hook replaced in a later layer const instruction& current_instruction() { return get(Recipe, Current_routine->running_recipe).steps.at(Current_routine->running_step_index); } //: hook replaced in a later layer bool routine::completed() const { return running_step_index >= SIZE(get(Recipe, running_recipe).steps); } //: hook replaced in a later layer const vector<instruction>& routine::steps() const { return get(Recipe, running_recipe).steps; } //:: Startup flow :(before "End Mu Prelude") load_file_or_directory("core.mu"); //? DUMP(""); //? exit(0); //: Step 2: load any .mu files provided at the commandline :(before "End Commandline Parsing") // Check For .mu Files if (argc > 1) { // skip argv[0] ++argv; --argc; while (argc > 0) { // ignore argv past '--'; that's commandline args for 'main' if (string(*argv) == "--") break; if (starts_with(*argv, "--")) cerr << "treating " << *argv << " as a file rather than an option\n"; load_file_or_directory(*argv); --argc; ++argv; } if (Run_tests) Recipe.erase(get(Recipe_ordinal, "main")); } transform_all(); //? cerr << to_original_string(get(Type_ordinal, "editor")) << '\n'; //? cerr << to_original_string(get(Recipe, get(Recipe_ordinal, "event-loop"))) << '\n'; //? DUMP(""); //? exit(0); if (trace_contains_errors()) return 1; if (Trace_stream && Run_tests) { // We'll want a trace per test. Clear the trace. delete Trace_stream; Trace_stream = NULL; } save_snapshots(); //: Step 3: if we aren't running tests, locate a recipe called 'main' and //: start running it. :(before "End Main") if (!Run_tests && contains_key(Recipe_ordinal, "main") && contains_key(Recipe, get(Recipe_ordinal, "main"))) { // Running Main reset(); trace(2, "run") << "=== Starting to run" << end(); assert(Num_calls_to_transform_all == 1); run_main(argc, argv); } :(code) void run_main(int argc, char* argv[]) { recipe_ordinal r = get(Recipe_ordinal, "main"); if (r) run(r); } void load_file_or_directory(string filename) { if (is_directory(filename)) { load_all(filename); return; } ifstream fin(filename.c_str()); if (!fin) { cerr << "no such file '" << filename << "'\n" << end(); // don't raise, just warn. just in case it's just a name for a test to run. return; } trace(2, "load") << "=== " << filename << end(); load(fin); fin.close(); } bool is_directory(string path) { struct stat info; if (stat(path.c_str(), &info)) return false; // error return info.st_mode & S_IFDIR; } void load_all(string dir) { dirent** files; int num_files = scandir(dir.c_str(), &files, NULL, alphasort); for (int i = 0; i < num_files; ++i) { string curr_file = files[i]->d_name; if (isdigit(curr_file.at(0)) && ends_with(curr_file, ".mu")) load_file_or_directory(dir+'/'+curr_file); free(files[i]); files[i] = NULL; } free(files); } bool ends_with(const string& s, const string& pat) { for (string::const_reverse_iterator p = s.rbegin(), q = pat.rbegin(); q != pat.rend(); ++p, ++q) { if (p == s.rend()) return false; // pat too long if (*p != *q) return false; } return true; } :(before "End Includes") #include <dirent.h> #include <sys/stat.h> //:: Reading from memory, writing to memory. :(code) vector<double> read_memory(reagent/*copy*/ x) { // Begin Preprocess read_memory(x) vector<double> result; if (x.name == "null") result.push_back(/*alloc id*/0); if (is_literal(x)) { result.push_back(x.value); return result; } // End Preprocess read_memory(x) int size = size_of(x); for (int offset = 0; offset < size; ++offset) { double val = get_or_insert(Memory, x.value+offset); trace(Callstack_depth+1, "mem") << "location " << x.value+offset << " is " << no_scientific(val) << end(); result.push_back(val); } return result; } void write_memory(reagent/*copy*/ x, const vector<double>& data) { assert(Current_routine); // run-time only // Begin Preprocess write_memory(x, data) if (!x.type) { raise << "can't write to '" << to_string(x) << "'; no type\n" << end(); return; } if (is_dummy(x)) return; if (is_literal(x)) return; // End Preprocess write_memory(x, data) if (x.value == 0) { raise << "can't write to location 0 in '" << to_original_string(current_instruction()) << "'\n" << end(); return; } if (size_mismatch(x, data)) { raise << maybe(current_recipe_name()) << "size mismatch in storing to '" << x.original_string << "' (" << size_of(x) << " vs " << SIZE(data) << ") at '" << to_original_string(current_instruction()) << "'\n" << end(); return; } // End write_memory(x) Special-cases for (int offset = 0; offset < SIZE(data); ++offset) { assert(x.value+offset > 0); trace(Callstack_depth+1, "mem") << "storing " << no_scientific(data.at(offset)) << " in location " << x.value+offset << end(); //? if (Foo) cerr << "mem: storing " << no_scientific(data.at(offset)) << " in location " << x.value+offset << '\n'; put(Memory, x.value+offset, data.at(offset)); } } :(code) int size_of(const reagent& r) { if (!r.type) return 0; // End size_of(reagent r) Special-cases return size_of(r.type); } int size_of(const type_tree* type) { if (!type) return 0; if (type->atom) { if (type->value == -1) return 1; // error value, but we'll raise it elsewhere if (type->value == 0) return 1; // End size_of(type) Atom Special-cases } else { if (!type->left->atom) { raise << "invalid type " << to_string(type) << '\n' << end(); return 0; } if (type->left->value == Address_type_ordinal) return 2; // address and alloc id // End size_of(type) Non-atom Special-cases } // End size_of(type) Special-cases return 1; } bool size_mismatch(const reagent& x, const vector<double>& data) { if (!x.type) return true; // End size_mismatch(x) Special-cases //? if (size_of(x) != SIZE(data)) cerr << size_of(x) << " vs " << SIZE(data) << '\n'; return size_of(x) != SIZE(data); } bool is_literal(const reagent& r) { return is_literal(r.type); } bool is_literal(const type_tree* type) { if (!type) return false; if (!type->atom) return false; return type->value == 0; } bool scalar(const vector<int>& x) { return SIZE(x) == 1; } bool scalar(const vector<double>& x) { return SIZE(x) == 1; } // helper for tests void run(const string& form) { vector<recipe_ordinal> tmp = load(form); transform_all(); if (tmp.empty()) return; if (trace_contains_errors()) return; // if a test defines main, it probably wants to start there regardless of // definition order if (contains_key(Recipe, get(Recipe_ordinal, "main"))) run(get(Recipe_ordinal, "main")); else run(tmp.front()); } void test_run_label() { run( "def main [\n" " +foo\n" " 1:num <- copy 23\n" " 2:num <- copy 1:num\n" "]\n" ); CHECK_TRACE_CONTENTS( "run: {1: \"number\"} <- copy {23: \"literal\"}\n" "run: {2: \"number\"} <- copy {1: \"number\"}\n" ); CHECK_TRACE_DOESNT_CONTAIN("run: +foo"); } void test_run_dummy() { run( "def main [\n" " _ <- copy 0\n" "]\n" ); CHECK_TRACE_CONTENTS( "run: _ <- copy {0: \"literal\"}\n" ); } void test_run_null() { run( "def main [\n" " 1:&:num <- copy null\n" "]\n" ); } void test_write_to_0_disallowed() { Hide_errors = true; run( "def main [\n" " 0:num <- copy 34\n" "]\n" ); CHECK_TRACE_DOESNT_CONTAIN("mem: storing 34 in location 0"); } //: Mu is robust to various combinations of commas and spaces. You just have //: to put spaces around the '<-'. void test_comma_without_space() { run( "def main [\n" " 1:num, 2:num <- copy 2,2\n" "]\n" ); CHECK_TRACE_CONTENTS( "mem: storing 2 in location 1\n" ); } void test_space_without_comma() { run( "def main [\n" " 1:num, 2:num <- copy 2 2\n" "]\n" ); CHECK_TRACE_CONTENTS( "mem: storing 2 in location 1\n" ); } void test_comma_before_space() { run( "def main [\n" " 1:num, 2:num <- copy 2, 2\n" "]\n" ); CHECK_TRACE_CONTENTS( "mem: storing 2 in location 1\n" ); } void test_comma_after_space() { run( "def main [\n" " 1:num, 2:num <- copy 2 ,2\n" "]\n" ); CHECK_TRACE_CONTENTS( "mem: storing 2 in location 1\n" ); } //:: Counters for trying to understand where Mu programs are spending their //:: time. :(before "End Globals") bool Run_profiler = false; // We'll key profile information by recipe_ordinal rather than name because // it's more efficient, and because later layers will show more than just the // name of a recipe. // // One drawback: if you're clearing recipes your profile will be inaccurate. // So far that happens in tests, and in 'run-sandboxed' in a later layer. map<recipe_ordinal, int> Instructions_running; :(before "End Commandline Options(*arg)") else if (is_equal(*arg, "--profile")) { Run_profiler = true; } :(after "Running One Instruction") if (Run_profiler) Instructions_running[currently_running_recipe()]++; :(before "End One-time Setup") atexit(dump_profile); :(code) void dump_profile() { if (!Run_profiler) return; if (Run_tests) { cerr << "It's not a good idea to profile a run with tests, since tests can create conflicting recipes and mislead you. To try it anyway, comment out this check in the code.\n"; return; } ofstream fout; fout.open("profile.instructions"); if (fout) { for (map<recipe_ordinal, int>::iterator p = Instructions_running.begin(); p != Instructions_running.end(); ++p) { fout << std::setw(9) << p->second << ' ' << header_label(p->first) << '\n'; } } fout.close(); // End dump_profile } // overridden in a later layer string header_label(const recipe_ordinal r) { return get(Recipe, r).name; }