Skip to content

Commit 97eb293

Browse files
committed
Version 1.0.0. Published in Esolangs on December 12, 2015
1 parent de3b447 commit 97eb293

File tree

15 files changed

+2094
-0
lines changed

15 files changed

+2094
-0
lines changed

MATL_spec.pdf

395 KB
Binary file not shown.

funDef.mat

24 KB
Binary file not shown.

funDef.txt

Lines changed: 563 additions & 0 deletions
Large diffs are not rendered by default.

genFunDef.m

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
function F = genFunDef(masterFileName, fileName)
2+
%
3+
% Generates function definition struct array "F" from tab-separated text
4+
% file, and saves it in file "funDef.mat"
5+
%
6+
% The tab-separated file has one or more lines for each function.
7+
% The first line for each function contains its source code in the first
8+
% column. If a function has the sixth column ("body") empty, the function
9+
% is considered to be undefined, and is not included in struct array "F".
10+
%
11+
% Wraps function body in a cell, even if it's a single string.
12+
% Function body in the text file may span several strings. This is defined
13+
% using subsequent lines with "source" column empty and "body" field
14+
% filled. In that case, this function collects all lines in a cell array of
15+
% strings.
16+
%
17+
% Luis Mendo.
18+
19+
fieldNames = {'source' 'minIn' 'maxIn' 'defIn' 'minOut' 'maxOut' 'defOut' 'consumeInputs' 'wrap' 'body' 'comment' 'description'};
20+
fid = fopen(masterFileName, 'r');
21+
F = reshape(fread(fid,inf,'*char'),1,[]);
22+
fclose(fid);
23+
F = reshape(regexp(F, '[\r\n]+', 'split'),[],1);
24+
ind = cellfun(@(s) ~isempty(s)&&s(1)~='%', F);
25+
F = F(ind);
26+
F = regexp(F, ' *\t *', 'split');
27+
n = numel(fieldNames);
28+
F = cellfun(@(s) [ s(1:min(n,end)) repmat({''},1,max(n-numel(s),0)) ], F, 'uniform', 0); % fill if empty columns
29+
F = vertcat(F{:});
30+
F = F(~cellfun(@isempty, F(:,10)),:); % remove functions that have a line in
31+
% the file but are not actually defined. These are identified because "body"
32+
% column is empty.
33+
34+
% Transform 'consumeInputs' and 'wrap' fields into logical values:
35+
for c = [8 9]
36+
for r = 1:size(F,1)
37+
F{r,c} = logical(str2num(F{r,c})); %#ok
38+
end
39+
end
40+
41+
% Join function body lines corresponding to the same function source into
42+
% a cell array of strings. Single lines are also wrapped into a cell array.
43+
d = [~cellfun('isempty', F(:,1)); true];
44+
starts = find(d(1:end-1));
45+
ends = find(d(2:end));
46+
for n = numel(starts):-1:1 % process from end because F will be shrunk along the way
47+
F{starts(n),10} = F(starts(n):ends(n),10).';
48+
F(starts(n)+1:ends(n),:) = [];
49+
end
50+
51+
assert(numel(unique(F(:,1)))==numel(F(:,1)), 'MATL:compiler:internal', 'MATL internal error while reading function definition file: function names are not unique')
52+
53+
F = cell2struct(F, fieldNames, 2);
54+
save(fileName, 'F')

genHelp.m

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
function H = genHelp(F, L)
2+
%
3+
% Generates help struct array "H" from struct array "F" (functions) and
4+
% additional information coded directly here (non-functions), and saves it
5+
% in file "help.mat"
6+
%
7+
% Luis Mendo.
8+
9+
10+
N = 65; % characters per line
11+
12+
% Non-functions. Changes done here should be don in `genHelp.m` too
13+
14+
% Statements that are not functions. Changes done here to the comment field should be
15+
% done in `matl_disp.m` too.
16+
F(end+1).source = '"';
17+
F(end).comment = 'for';
18+
F(end).description = '\matlab+for+ (control flow: loop). \sa \matl+]+, \matl+@+, \matl+X}+, \matl+Y}+';
19+
20+
F(end+1).source = '`';
21+
F(end).comment = 'do...while';
22+
F(end).description = 'do...while (control flow: loop). \sa \matl+X`+, \matl+]+, \matl+@+, \matl+X}+, \matl+Y}+';
23+
24+
F(end+1).source = 'X`';
25+
F(end).comment = 'while';
26+
F(end).description = '\matlab+while+ (control flow: loop). \sa \matl+`+, \matl+]+, \matl+@+, \matl+X}+, \matl+Y}+';
27+
28+
F(end+1).source = '?';
29+
F(end).comment = 'if';
30+
F(end).description = '\matlab+if+ (control flow: conditional branch). \sa \matl+]+, \matl+}+';
31+
32+
F(end+1).source = '}';
33+
F(end).comment = 'else';
34+
F(end).description = '\matlab+else+ (control flow: conditional branch). \sa \matl+?+';
35+
36+
F(end+1).source = '@';
37+
F(end).comment = 'for loop variable or do...while / while loop iteration index';
38+
F(end).description = 'for loop variable, do...while loop iteration index or while loop iteration index of innermost loop';
39+
40+
F(end+1).source = ']';
41+
F(end).comment = 'end';
42+
F(end).description = '\matlab+end+ (control flow). End loop or conditional branch. \sa \matl+"+, \matl+`+, \matl+?+';
43+
44+
F(end+1).source = '.';
45+
F(end).comment = 'conditional break';
46+
F(end).description = 'conditional \matlab+break+ (control flow: loop). Consume the top of the stack and, if it evaluates to ''true'' acccording to \matlab+if+ rules, terminate execution of innermost loop. \sa \matl+"+, \matl+`+';
47+
48+
F(end+1).source = 'X.';
49+
F(end).comment = 'conditional continue';
50+
F(end).description = 'conditional \matlab+continue+ (control flow: loop). Consume the top of the stack and, if it evaluates to ''true'' acccording to \matlab+if+ rules, pass control to next iteration of innermost loop. \sa \matl+"+, \matl+`+';
51+
52+
F(end+1).source = '''';
53+
F(end).comment = 'string delimiter';
54+
F(end).description = 'string delimiter. Should be doubled when used within a string';
55+
56+
F(end+1).source = ',';
57+
F(end).comment = 'separator';
58+
F(end).description = 'separator. Space and newline can be used as separators too';
59+
60+
F(end+1).source = '%';
61+
F(end).comment = 'comment';
62+
F(end).description = 'comment. The rest of the line is ignored';
63+
64+
% Sort according to source
65+
[~, ind] = sort(cellfun(@(x) x(end:-1:1), {F.source}, 'UniformOutput', 0));
66+
F = F(ind);
67+
68+
commFormatted = {F.comment};
69+
descrFormatted = {F.description};
70+
descrFormatted = regexprep(descrFormatted, '\\matlab(.)(.*?)(\1)', '<strong>$2</strong>');
71+
descrFormatted = regexprep(descrFormatted, '\\matl\+(.*?)\+', '<strong>$1</strong>'); %***make delimiter arbitrary her too
72+
descrFormatted = regexprep(descrFormatted, '\\comp{(.*?)}', '<strong>$1</strong>');
73+
descrFormatted = regexprep(descrFormatted, '\\sa', 'See also');
74+
descrFormatted = regexprep(descrFormatted, '\$(.*?)\$', '$1');
75+
descrPlain = cell(1,numel(descrFormatted));
76+
inFormatted = cell(1,numel(descrFormatted));
77+
outFormatted = cell(1,numel(descrFormatted));
78+
sourceFormatted = cell(1,numel(descrFormatted));
79+
sourcePlain = {F.source};
80+
81+
for n = 1:numel(descrFormatted)
82+
% Format source
83+
sourceFormatted{n} = ['<strong>' F(n).source '</strong>'];
84+
85+
% Add information on predefined literals, if applicable
86+
if ~isempty(regexp(F(n).source,'[XYZ]\d','once')) && isfield(L, (F(n).source)) % X0...Z9 that are defined
87+
aux = [num2cell(L.(F(n).source).key); L.(F(n).source).val];
88+
descrFormatted{n} = [ descrFormatted{n} '. ' sprintf('%i: %s; ', aux{:})];
89+
end
90+
91+
% Format description
92+
descrFormatted{n}(end+1) = ' '; % needed so that the "find" line always finds last index
93+
[s, e] = regexp(descrFormatted{n},'<strong>','start','end');
94+
descrMask = true(1,numel(descrFormatted{n}));
95+
descrSpace = false(1,numel(descrFormatted{n}));
96+
for m = 1:numel(s)
97+
descrMask(s(m):e(m)) = false;
98+
end
99+
[s, e] = regexp(descrFormatted{n},'</strong>','start','end');
100+
for m = 1:numel(s)
101+
descrMask(s(m):e(m)) = false;
102+
end
103+
descrPlain{n} = descrFormatted{n}(descrMask);
104+
s = regexp(descrFormatted{n},'\s','start');
105+
descrSpace(s) = true;
106+
d = {};
107+
while ~isempty(descrMask)
108+
c = cumsum(descrMask);
109+
ind = find((c<=N)& descrSpace, 1, 'last');
110+
d{end+1} = descrFormatted{n}(1:ind);
111+
descrFormatted{n}(1:ind) = [];
112+
descrMask(1:ind) = [];
113+
descrSpace(1:ind) = [];
114+
end
115+
% descrFormatted{n} = char(d); % gives a char 2D array. Bad for searching
116+
d = sprintf(' %s\n', d{:}); % four spaces for left margin
117+
descrFormatted{n} = d(1:end-1); % remove last '\n'
118+
119+
% Format input spec:
120+
minIn = str2double(F(n).minIn);
121+
maxIn = str2double(F(n).maxIn);
122+
defIn = str2double(F(n).defIn);
123+
minOut = str2double(F(n).minOut);
124+
maxOut = str2double(F(n).maxOut);
125+
defOut = str2double(F(n).defOut);
126+
127+
if isnan(defIn) && ~isempty(F(n).defIn) % F(n).defIn contains a string that couldn't be converted to a number
128+
switch F(n).defIn
129+
case 'numel(STACK)'
130+
defInStr = 'number of elements in stack';
131+
otherwise
132+
error('Unrecognized default number of inputs')
133+
end
134+
else
135+
defInStr = sprintf('%i', defIn);
136+
end
137+
138+
if isempty(F(n).minIn) || isempty(F(n).maxIn)
139+
inFormatted{n} = [];
140+
elseif minIn ~= maxIn
141+
if isfinite(maxIn)
142+
inFormatted{n} = sprintf('%i--%i (%s)', minIn, maxIn, defInStr);
143+
else
144+
inFormatted{n} = sprintf('%i-- (%s)', minIn, defInStr);
145+
end
146+
else
147+
if maxIn ~= defIn
148+
error('Incorrect specification of number of inputs')
149+
end
150+
inFormatted{n} = sprintf('%i', defIn);
151+
end
152+
153+
% Format output spec:
154+
if isnan(defOut) && ~isempty(F(n).defOut) % F(n).defOut contains a string that couldn't be converted to a number
155+
switch F(n).defOut
156+
case {'numel(CB_H)' 'numel(CB_I)' 'numel(CB_J)' 'numel(CB_K)'}
157+
defOutStr = 'number of elements in clipboard';
158+
case 'numel(CB_L{in{1}})'
159+
defOutStr = 'number of elements in clipboard level';
160+
case 'numel(in{1})'
161+
defOutStr = 'number of elements of first input';
162+
otherwise
163+
error('Unrecognized default number of outputs')
164+
end
165+
else
166+
defOutStr = sprintf('%i', defOut);
167+
end
168+
169+
if isempty(F(n).minOut) || isempty(F(n).maxOut)
170+
outFormatted{n} = [];
171+
elseif minOut ~= maxOut
172+
if isfinite(maxOut)
173+
outFormatted{n} = sprintf('%i--%i (%s)', minOut, maxOut, defOutStr);
174+
else
175+
outFormatted{n} = sprintf('%i-- (%s)', minOut, defOutStr);
176+
end
177+
else
178+
if maxOut ~= defOut
179+
error('Incorrect specification of number of inputs')
180+
end
181+
outFormatted{n} = sprintf('%i', defOut);
182+
end
183+
end
184+
185+
H.source = sourceFormatted;
186+
H.comm = commFormatted;
187+
H.descr = descrFormatted;
188+
H.in = inFormatted;
189+
H.out = outFormatted;
190+
H.sourcePlain = sourcePlain;
191+
H.descrPlain = descrPlain;
192+
save help H
193+
194+

genPreLit.m

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function L = genPreLit(masterFileName, fileName)
2+
3+
fid = fopen(masterFileName, 'r');
4+
p = reshape(fread(fid,inf,'*char'),1,[]);
5+
fclose(fid);
6+
p = regexp(p, '[\r\n]+', 'split');
7+
p = p(~cellfun(@isempty, p));
8+
funNamesInd = [ find(cellfun(@(x) isempty(regexp(x, '\t', 'once')), p)) numel(p)+1];
9+
for n = 1:numel(funNamesInd)-1
10+
foundKeys = [];
11+
for k = funNamesInd(n)+1:funNamesInd(n+1)-1
12+
kv = regexp(p{k}, '\t+', 'split');
13+
key = str2double(kv{1});
14+
assert(~any(foundKeys==key), 'MATL:compiler:internal', 'MATL internal error while reading predefind literal file: key values are not unique')
15+
val = kv{2};
16+
foundKeys(end+1) = key;
17+
c = numel(foundKeys);
18+
L.(p{funNamesInd(n)}).key(c) = key;
19+
L.(p{funNamesInd(n)}).val{c} = val;
20+
end
21+
end
22+
23+
save(fileName, 'L')
24+
25+
26+
27+

help.mat

17.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)