nk
1.0.0
C++ Numerical Computing Runtime
Toggle main menu visibility
Loading...
Searching...
No Matches
function_file.hpp
1
// runtime/include/nk/runtime/function_file.hpp
2
//
3
// MATLAB `run`/file-execution semantics for FUNCTION files
4
// (bugs/opened/lang/run-invokes-nullary-function-file.md): a file whose
5
// first code construct is a function definition EXECUTES that function
6
// when run — a nullary function runs to completion; a function with
7
// required inputs is still CALLED and fails with the natural
8
// "not enough input arguments" (exactly what MATLAB R2025b does —
9
// verified on the fieldtest corpus: extract_firms_data.m).
10
//
11
// Header-only: shared by the `run` builtin (runtime) and the native CLI
12
// (apps/nk); the WASM CLI mirrors the same scan in JS.
13
14
#pragma once
15
16
#include <cctype>
17
#include <string>
18
19
namespace
nk::runtime {
20
21
// Returns true and fills `name` with the PRIMARY function's identifier if
22
// `src` is a function file (first non-comment, non-blank construct is a
23
// function definition). Returns false for scripts.
24
inline
bool
primaryFunctionOfFile(
const
std::string &src, std::string &name)
25
{
26
std::string line;
27
bool
haveFirst =
false
;
28
size_t
i = 0;
29
const
size_t
n = src.size();
30
auto
trim = [](std::string &s) {
31
size_t
a = 0, b = s.size();
32
while
(a < b && std::isspace(
static_cast<
unsigned
char
>
(s[a]))) ++a;
33
while
(b > a && std::isspace(
static_cast<
unsigned
char
>
(s[b - 1]))) --b;
34
s = s.substr(a, b - a);
35
};
36
while
(i < n && !haveFirst) {
37
// read one physical line
38
line.clear();
39
while
(i < n && src[i] !=
'\n'
) line += src[i++];
40
if
(i < n) ++i;
41
while
(!line.empty() && (line.back() ==
'\r'
)) line.pop_back();
42
// strip a trailing comment (naive: first '%' — function signature
43
// lines do not carry literal % in strings in practice)
44
size_t
pct = line.find(
'%'
);
45
if
(pct != std::string::npos) line.resize(pct);
46
trim(line);
47
if
(line.empty())
continue
;
48
if
(line.rfind(
"function"
, 0) == 0
49
&& (line.size() == 8 || std::isspace(
static_cast<
unsigned
char
>
(line[8])))) {
50
haveFirst =
true
;
51
// join continuations ("...") of the signature line
52
while
(line.size() >= 3 && line.compare(line.size() - 3, 3,
"..."
) == 0 && i < n) {
53
line.resize(line.size() - 3);
54
std::string more;
55
while
(i < n && src[i] !=
'\n'
) more += src[i++];
56
if
(i < n) ++i;
57
size_t
p = more.find(
'%'
);
58
if
(p != std::string::npos) more.resize(p);
59
trim(more);
60
line += more;
61
}
62
}
else
{
63
return
false
;
// first code construct is not a function → script
64
}
65
}
66
if
(!haveFirst)
67
return
false
;
68
69
// Parse the signature: function [out] = name(args) | function name(args)
70
size_t
eq
= line.find(
'='
);
71
size_t
namePos = std::string::npos;
72
if
(eq != std::string::npos) {
73
// ensure the '=' is before any '(' (output-list form)
74
size_t
lp = line.find(
'('
);
75
if
(lp != std::string::npos && lp < eq)
eq
= std::string::npos;
76
}
77
if
(eq != std::string::npos) {
78
namePos =
eq
+ 1;
79
}
else
{
80
namePos = 8;
// past "function"
81
}
82
while
(namePos < line.size() && std::isspace(
static_cast<
unsigned
char
>
(line[namePos])))
83
++namePos;
84
if
(namePos >= line.size())
return
false
;
85
if
(!std::isalpha(
static_cast<
unsigned
char
>
(line[namePos])) && line[namePos] !=
'_'
)
86
return
false
;
87
size_t
end = namePos;
88
while
(end < line.size()
89
&& (std::isalnum(
static_cast<
unsigned
char
>
(line[end])) || line[end] ==
'_'
))
90
++end;
91
name = line.substr(namePos, end - namePos);
92
return
!name.empty();
93
}
94
95
}
// namespace nk::runtime
nk::builtin::eq
Value eq(const Value &a, const Value &b, std::pmr::memory_resource *mr=nullptr)
Elementwise equality (y = a == b).
src
runtime
include
nk
runtime
function_file.hpp
Generated by
1.17.0