arc-lang 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -130
- package/dist/ast.d.ts +30 -2
- package/dist/build.js +1 -1
- package/dist/formatter.js +15 -3
- package/dist/index.js +104 -0
- package/dist/interpreter.js +130 -17
- package/dist/lexer.d.ts +41 -37
- package/dist/lexer.js +47 -39
- package/dist/linter.js +18 -0
- package/dist/modules.js +5 -1
- package/dist/parser.d.ts +2 -0
- package/dist/parser.js +91 -11
- package/dist/repl.js +66 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -2
- package/stdlib/API_DESIGN.md +357 -0
- package/stdlib/ASYNC_DESIGN.md +815 -0
- package/stdlib/EXAMPLES.md +710 -0
- package/stdlib/MODULES.md +854 -0
- package/stdlib/README.md +64 -0
- package/stdlib/collections.arc +140 -0
- package/stdlib/crypto.arc +62 -0
- package/stdlib/csv.arc +40 -0
- package/stdlib/datetime.arc +75 -0
- package/stdlib/embed.arc +42 -0
- package/stdlib/env.arc +10 -0
- package/stdlib/error.arc +36 -0
- package/stdlib/html.arc +30 -0
- package/stdlib/http.arc +43 -0
- package/stdlib/io.arc +28 -0
- package/stdlib/json.arc +204 -0
- package/stdlib/llm.arc +193 -0
- package/stdlib/log.arc +20 -0
- package/stdlib/map.arc +72 -0
- package/stdlib/math.arc +133 -0
- package/stdlib/net.arc +17 -0
- package/stdlib/os.arc +81 -0
- package/stdlib/path.arc +11 -0
- package/stdlib/prompt.arc +49 -0
- package/stdlib/regex.arc +59 -0
- package/stdlib/result.arc +50 -0
- package/stdlib/store.arc +62 -0
- package/stdlib/strings.arc +44 -0
- package/stdlib/test.arc +61 -0
- package/stdlib/time.arc +19 -0
- package/stdlib/toml.arc +10 -0
- package/stdlib/yaml.arc +10 -0
package/stdlib/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Arc Standard Library
|
|
2
|
+
|
|
3
|
+
The Arc standard library provides essential modules for common programming tasks, designed with Arc's token-efficiency philosophy.
|
|
4
|
+
|
|
5
|
+
## Modules
|
|
6
|
+
|
|
7
|
+
| Module | Status | File | Description |
|
|
8
|
+
|--------|--------|------|-------------|
|
|
9
|
+
| **math** | ✅ Implemented | [`math.arc`](math.arc) | Constants (PI, E) and functions (abs, pow, sqrt, ceil, floor, clamp) |
|
|
10
|
+
| **strings** | ✅ Implemented | [`strings.arc`](strings.arc) | String utilities (pad_left, pad_right, capitalize, words) |
|
|
11
|
+
| **collections** | ✅ Implemented | [`collections.arc`](collections.arc) | List utilities (set, unique, group_by, chunk, flatten, zip_with, partition, sort_by) |
|
|
12
|
+
| **map** | ✅ Implemented | [`map.arc`](map.arc) | Map utilities (merge, map_values, filter_map, from_pairs, pick, omit) |
|
|
13
|
+
| **io** | ✅ Implemented | [`io.arc`](io.arc) | File I/O (read_lines, write_lines, exists, append) |
|
|
14
|
+
| **http** | ✅ Implemented | [`http.arc`](http.arc) | HTTP client (get, post, put, delete, fetch_all, parse_url) |
|
|
15
|
+
| **json** | ✅ Implemented | [`json.arc`](json.arc) | JSON parser/serializer (to_json, from_json, pretty, get_path) |
|
|
16
|
+
| **csv** | ✅ Implemented | [`csv.arc`](csv.arc) | CSV parser/serializer (parse_csv, to_csv, parse_csv_headers) |
|
|
17
|
+
| **test** | ✅ Implemented | [`test.arc`](test.arc) | Testing framework (describe, it, expect_eq, expect_true, run_tests) |
|
|
18
|
+
| **result** | ✅ Implemented | [`result.arc`](result.arc) | Result type (ok, err, is_ok, unwrap, map_result, try_fn) |
|
|
19
|
+
| **time** | ✅ Implemented | [`time.arc`](time.arc) | Time utilities (now, format_duration, sleep) |
|
|
20
|
+
|
|
21
|
+
## Quick Examples
|
|
22
|
+
|
|
23
|
+
### math
|
|
24
|
+
|
|
25
|
+
```arc
|
|
26
|
+
use math
|
|
27
|
+
|
|
28
|
+
math.sqrt(144) # => 12
|
|
29
|
+
math.clamp(15, 0, 10) # => 10
|
|
30
|
+
math.PI # => 3.141592653589793
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### strings
|
|
34
|
+
|
|
35
|
+
```arc
|
|
36
|
+
use strings
|
|
37
|
+
|
|
38
|
+
strings.pad_left("7", 3, "0") # => "007"
|
|
39
|
+
strings.capitalize("hello") # => "Hello"
|
|
40
|
+
strings.words("one two three") # => ["one", "two", "three"]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Built-in Functions (No Import)
|
|
44
|
+
|
|
45
|
+
Many common operations are built into Arc and need no `use` statement:
|
|
46
|
+
|
|
47
|
+
`print`, `len`, `str`, `int`, `float`, `type`, `split`, `join`, `trim`, `upper`, `lower`, `slice`, `map`, `filter`, `reduce`, `find`, `contains`, `push`, `concat`, `take`, `skip`, `sort`, `reverse`, `keys`, `values`
|
|
48
|
+
|
|
49
|
+
## Documentation
|
|
50
|
+
|
|
51
|
+
- **[Standard Library Reference](../docs/stdlib-reference.md)** — Full API reference
|
|
52
|
+
- **[Standard Library Tutorial](../docs/stdlib-tutorial.md)** — Hands-on usage guide
|
|
53
|
+
|
|
54
|
+
## Design Principles
|
|
55
|
+
|
|
56
|
+
1. **Minimal but complete** — Cover common use cases without bloat
|
|
57
|
+
2. **Token-efficient** — Short names, clear APIs
|
|
58
|
+
3. **Pipeline-friendly** — Functions work naturally with `|>`
|
|
59
|
+
4. **Well-documented** — Every function has examples
|
|
60
|
+
5. **Consistent** — Similar operations have similar signatures
|
|
61
|
+
|
|
62
|
+
## Contributing
|
|
63
|
+
|
|
64
|
+
Help implement the planned modules! See [CONTRIBUTING.md](../CONTRIBUTING.md).
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Arc Standard Library: collections module
|
|
2
|
+
# Advanced collection utilities
|
|
3
|
+
|
|
4
|
+
pub fn set(list) {
|
|
5
|
+
let mut result = []
|
|
6
|
+
for item in list {
|
|
7
|
+
if not contains(result, item) {
|
|
8
|
+
result = push(result, item)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
result
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pub fn unique(list) => set(list)
|
|
15
|
+
|
|
16
|
+
pub fn group_by(list, f) {
|
|
17
|
+
let mut result = {}
|
|
18
|
+
for item in list {
|
|
19
|
+
let key = str(f(item))
|
|
20
|
+
let existing = if contains(keys(result), key) { result[key] } el { [] }
|
|
21
|
+
result[key] = push(existing, item)
|
|
22
|
+
}
|
|
23
|
+
result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn count_by(list, f) {
|
|
27
|
+
let mut result = {}
|
|
28
|
+
for item in list {
|
|
29
|
+
let key = str(f(item))
|
|
30
|
+
let existing = if contains(keys(result), key) { result[key] } el { 0 }
|
|
31
|
+
result[key] = existing + 1
|
|
32
|
+
}
|
|
33
|
+
result
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn chunk(list, size) {
|
|
37
|
+
if size <= 0 { [] }
|
|
38
|
+
el if len(list) == 0 { [] }
|
|
39
|
+
el {
|
|
40
|
+
let mut result = []
|
|
41
|
+
let mut i = 0
|
|
42
|
+
do {
|
|
43
|
+
let end = if i + size > len(list) { len(list) } el { i + size }
|
|
44
|
+
result = push(result, slice(list, i, end))
|
|
45
|
+
i = i + size
|
|
46
|
+
} until i >= len(list)
|
|
47
|
+
result
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fn flatten(list) => flat(list)
|
|
52
|
+
|
|
53
|
+
pub fn zip_with(a, b, f) {
|
|
54
|
+
let mut result = []
|
|
55
|
+
let pairs = zip(a, b)
|
|
56
|
+
for p in pairs {
|
|
57
|
+
result = push(result, f(p[0], p[1]))
|
|
58
|
+
}
|
|
59
|
+
result
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn partition(list, f) {
|
|
63
|
+
let passing = filter(list, f)
|
|
64
|
+
let not_f = x => not f(x)
|
|
65
|
+
let failing = filter(list, not_f)
|
|
66
|
+
let result = [passing, failing]
|
|
67
|
+
result
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn frequencies(list) {
|
|
71
|
+
let mut result = {}
|
|
72
|
+
for item in list {
|
|
73
|
+
let key = str(item)
|
|
74
|
+
let existing = if contains(keys(result), key) { result[key] } el { 0 }
|
|
75
|
+
result[key] = existing + 1
|
|
76
|
+
}
|
|
77
|
+
result
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn min_by(list, f) {
|
|
81
|
+
if len(list) == 0 { nil }
|
|
82
|
+
el {
|
|
83
|
+
let mut best = list[0]
|
|
84
|
+
let mut best_val = f(best)
|
|
85
|
+
for i in 1..len(list) {
|
|
86
|
+
let val = f(list[i])
|
|
87
|
+
if val < best_val {
|
|
88
|
+
best = list[i]
|
|
89
|
+
best_val = val
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
best
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
pub fn max_by(list, f) {
|
|
97
|
+
if len(list) == 0 { nil }
|
|
98
|
+
el {
|
|
99
|
+
let mut best = list[0]
|
|
100
|
+
let mut best_val = f(best)
|
|
101
|
+
for i in 1..len(list) {
|
|
102
|
+
let val = f(list[i])
|
|
103
|
+
if val > best_val {
|
|
104
|
+
best = list[i]
|
|
105
|
+
best_val = val
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
best
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub fn sort_by(list, f) {
|
|
113
|
+
# Insertion sort by key function
|
|
114
|
+
let mut arr = map(list, x => x)
|
|
115
|
+
for i in 1..len(arr) {
|
|
116
|
+
let mut j = i
|
|
117
|
+
do {
|
|
118
|
+
if j <= 0 { j = 0 }
|
|
119
|
+
el if f(arr[j]) < f(arr[j - 1]) {
|
|
120
|
+
let tmp = arr[j]
|
|
121
|
+
arr[j] = arr[j - 1]
|
|
122
|
+
arr[j - 1] = tmp
|
|
123
|
+
j = j - 1
|
|
124
|
+
} el { j = 0 }
|
|
125
|
+
} until j <= 0
|
|
126
|
+
}
|
|
127
|
+
arr
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pub fn index_of(list, val) {
|
|
131
|
+
let mut result = nil
|
|
132
|
+
for i in 0..len(list) {
|
|
133
|
+
if list[i] == val and result == nil {
|
|
134
|
+
result = i
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
pub fn includes(list, val) => contains(list, val)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Arc Standard Library: crypto module
|
|
2
|
+
# Hashing, encryption, and cryptographic utilities
|
|
3
|
+
|
|
4
|
+
# --- Hashing ---
|
|
5
|
+
|
|
6
|
+
pub fn md5(text) => crypto_hash("md5", text)
|
|
7
|
+
pub fn sha1(text) => crypto_hash("sha1", text)
|
|
8
|
+
pub fn sha256(text) => crypto_hash("sha256", text)
|
|
9
|
+
pub fn sha512(text) => crypto_hash("sha512", text)
|
|
10
|
+
|
|
11
|
+
# --- HMAC ---
|
|
12
|
+
|
|
13
|
+
pub fn hmac_sha256(key, message) => crypto_hmac("sha256", key, message)
|
|
14
|
+
pub fn hmac_sha512(key, message) => crypto_hmac("sha512", key, message)
|
|
15
|
+
|
|
16
|
+
# --- Random ---
|
|
17
|
+
|
|
18
|
+
pub fn random_bytes(n) {
|
|
19
|
+
if n < 0 { panic("random_bytes: n must be non-negative") }
|
|
20
|
+
el { crypto_random_bytes(n) }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn random_int(min, max) {
|
|
24
|
+
if min > max { panic("random_int: min must be <= max") }
|
|
25
|
+
el { crypto_random_int(min, max) }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn uuid() => crypto_uuid()
|
|
29
|
+
|
|
30
|
+
# --- Base64 ---
|
|
31
|
+
|
|
32
|
+
pub fn base64_encode(text) => crypto_encode_base64(text)
|
|
33
|
+
pub fn base64_decode(text) => crypto_decode_base64(text)
|
|
34
|
+
|
|
35
|
+
# --- Password Hashing ---
|
|
36
|
+
|
|
37
|
+
pub fn hash_password(password, salt) {
|
|
38
|
+
let input = salt ++ ":" ++ password
|
|
39
|
+
let mut hash = sha256(input)
|
|
40
|
+
for i in 0..100 {
|
|
41
|
+
hash = sha256(hash ++ salt)
|
|
42
|
+
}
|
|
43
|
+
hash
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub fn verify_password(password, salt, hash) {
|
|
47
|
+
let computed = hash_password(password, salt)
|
|
48
|
+
computed == hash
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# --- Utility ---
|
|
52
|
+
|
|
53
|
+
pub fn constant_time_eq(a, b) {
|
|
54
|
+
if len(a) != len(b) { false }
|
|
55
|
+
el {
|
|
56
|
+
let mut result = true
|
|
57
|
+
for i in 0..len(a) {
|
|
58
|
+
if char_at(a, i) != char_at(b, i) { result = false }
|
|
59
|
+
}
|
|
60
|
+
result
|
|
61
|
+
}
|
|
62
|
+
}
|
package/stdlib/csv.arc
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Arc Standard Library: csv module
|
|
2
|
+
# CSV utilities (pure string manipulation)
|
|
3
|
+
|
|
4
|
+
pub fn parse_csv(text) => __native("csv.parse", text)
|
|
5
|
+
|
|
6
|
+
pub fn to_csv(rows) {
|
|
7
|
+
join(map(rows, row => join(map(row, cell => _escape_csv(str(cell))), ",")), "\n")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
pub fn parse_csv_headers(text) {
|
|
11
|
+
let rows = __native("csv.parse", text)
|
|
12
|
+
if len(rows) < 2 { [] }
|
|
13
|
+
el {
|
|
14
|
+
let headers = head(rows)
|
|
15
|
+
let data_rows = tail(rows)
|
|
16
|
+
map(data_rows, cells => {
|
|
17
|
+
let mut row = {}
|
|
18
|
+
for i in 0..len(headers) {
|
|
19
|
+
let key = trim(headers[i])
|
|
20
|
+
let val = if i < len(cells) { cells[i] } el { "" }
|
|
21
|
+
row[key] = val
|
|
22
|
+
}
|
|
23
|
+
row
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fn _parse_csv_line(line) {
|
|
29
|
+
# Simple CSV: split by comma, trim each cell
|
|
30
|
+
let cells = split(line, ",")
|
|
31
|
+
map(cells, cell => trim(cell))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn _escape_csv(s) {
|
|
35
|
+
if contains(s, ",") or contains(s, "\"") or contains(s, "\n") {
|
|
36
|
+
"\"" ++ replace(s, "\"", "\"\"") ++ "\""
|
|
37
|
+
} el {
|
|
38
|
+
s
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Arc Standard Library: datetime module
|
|
2
|
+
# Comprehensive date and time utilities
|
|
3
|
+
|
|
4
|
+
# Constants
|
|
5
|
+
let MS_PER_MINUTE = 60000
|
|
6
|
+
let MS_PER_HOUR = 3600000
|
|
7
|
+
let MS_PER_DAY = 86400000
|
|
8
|
+
|
|
9
|
+
# Returns the current timestamp in milliseconds since Unix epoch
|
|
10
|
+
pub fn now() => __builtin_now()
|
|
11
|
+
|
|
12
|
+
# Returns today's date as a map {year, month, day}
|
|
13
|
+
pub fn today() {
|
|
14
|
+
let ts = now()
|
|
15
|
+
let days = int(ts / MS_PER_DAY)
|
|
16
|
+
__builtin_date_from_ts(ts)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Parse a date string with the given format to a timestamp
|
|
20
|
+
# Format tokens: YYYY, MM, DD, hh, mm, ss
|
|
21
|
+
pub fn parse(date_string, format) => __builtin_date_parse(date_string, format)
|
|
22
|
+
|
|
23
|
+
# Format a timestamp to a string using the given format
|
|
24
|
+
# Format tokens: YYYY, MM, DD, hh, mm, ss
|
|
25
|
+
pub fn format(timestamp, format_string) => __builtin_date_format(timestamp, format_string)
|
|
26
|
+
|
|
27
|
+
# Add days to a timestamp, returns new timestamp
|
|
28
|
+
pub fn add_days(timestamp, days) => timestamp + days * MS_PER_DAY
|
|
29
|
+
|
|
30
|
+
# Add hours to a timestamp, returns new timestamp
|
|
31
|
+
pub fn add_hours(timestamp, hours) => timestamp + hours * MS_PER_HOUR
|
|
32
|
+
|
|
33
|
+
# Add minutes to a timestamp, returns new timestamp
|
|
34
|
+
pub fn add_minutes(timestamp, minutes) => timestamp + minutes * MS_PER_MINUTE
|
|
35
|
+
|
|
36
|
+
# Difference in days between two timestamps (absolute value)
|
|
37
|
+
pub fn diff_days(ts1, ts2) {
|
|
38
|
+
let diff = ts1 - ts2
|
|
39
|
+
let abs_diff = if diff < 0 { 0 - diff } el { diff }
|
|
40
|
+
int(abs_diff / MS_PER_DAY)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Difference in hours between two timestamps (absolute value)
|
|
44
|
+
pub fn diff_hours(ts1, ts2) {
|
|
45
|
+
let diff = ts1 - ts2
|
|
46
|
+
let abs_diff = if diff < 0 { 0 - diff } el { diff }
|
|
47
|
+
int(abs_diff / MS_PER_HOUR)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Difference in minutes between two timestamps (absolute value)
|
|
51
|
+
pub fn diff_minutes(ts1, ts2) {
|
|
52
|
+
let diff = ts1 - ts2
|
|
53
|
+
let abs_diff = if diff < 0 { 0 - diff } el { diff }
|
|
54
|
+
int(abs_diff / MS_PER_MINUTE)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Returns the day of the week (0 = Sunday, 6 = Saturday)
|
|
58
|
+
pub fn day_of_week(timestamp) {
|
|
59
|
+
# Jan 1 1970 was a Thursday (4)
|
|
60
|
+
let days = int(timestamp / MS_PER_DAY)
|
|
61
|
+
let result = ((days + 4) % 7 + 7) % 7
|
|
62
|
+
result
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Returns true if ts1 is before ts2
|
|
66
|
+
pub fn is_before(ts1, ts2) => ts1 < ts2
|
|
67
|
+
|
|
68
|
+
# Returns true if ts1 is after ts2
|
|
69
|
+
pub fn is_after(ts1, ts2) => ts1 > ts2
|
|
70
|
+
|
|
71
|
+
# Convert a timestamp to an ISO 8601 string
|
|
72
|
+
pub fn to_iso(timestamp) => __builtin_date_to_iso(timestamp)
|
|
73
|
+
|
|
74
|
+
# Parse an ISO 8601 string to a timestamp
|
|
75
|
+
pub fn from_iso(iso_string) => __builtin_date_from_iso(iso_string)
|
package/stdlib/embed.arc
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Arc Standard Library: embed module
|
|
2
|
+
# Vector embeddings, similarity search, and text chunking
|
|
3
|
+
|
|
4
|
+
# --- Vector Math (native implementations for performance) ---
|
|
5
|
+
|
|
6
|
+
pub fn dot_product(vec_a, vec_b) => embed_dot_product(vec_a, vec_b)
|
|
7
|
+
|
|
8
|
+
pub fn magnitude(vec) => embed_magnitude(vec)
|
|
9
|
+
|
|
10
|
+
pub fn cosine_similarity(vec_a, vec_b) => embed_cosine_similarity(vec_a, vec_b)
|
|
11
|
+
|
|
12
|
+
pub fn normalize(vec) => embed_normalize(vec)
|
|
13
|
+
|
|
14
|
+
pub fn euclidean_distance(vec_a, vec_b) => embed_euclidean_distance(vec_a, vec_b)
|
|
15
|
+
|
|
16
|
+
pub fn centroid(vectors) => embed_centroid(vectors)
|
|
17
|
+
|
|
18
|
+
# --- Similarity Search ---
|
|
19
|
+
|
|
20
|
+
# Find top_k most similar vectors from candidates list
|
|
21
|
+
# candidates: list of {id, vector} maps
|
|
22
|
+
# Returns: list of {id, score} maps sorted by similarity (descending)
|
|
23
|
+
pub fn most_similar(query_vec, candidates, top_k) => embed_most_similar(query_vec, candidates, top_k)
|
|
24
|
+
|
|
25
|
+
# --- Text Chunking ---
|
|
26
|
+
|
|
27
|
+
# Split text into chunks of approximately chunk_size characters
|
|
28
|
+
# Returns list of {chunk, index} maps
|
|
29
|
+
pub fn chunk_and_embed(text, chunk_size) {
|
|
30
|
+
let mut chunks = []
|
|
31
|
+
let mut i = 0
|
|
32
|
+
let text_len = len(text)
|
|
33
|
+
let mut idx = 0
|
|
34
|
+
do {
|
|
35
|
+
let end = if i + chunk_size > text_len { text_len } el { i + chunk_size }
|
|
36
|
+
let chunk = slice(text, i, end)
|
|
37
|
+
chunks = push(chunks, {chunk: chunk, index: idx})
|
|
38
|
+
i = i + chunk_size
|
|
39
|
+
idx = idx + 1
|
|
40
|
+
} until i >= text_len
|
|
41
|
+
chunks
|
|
42
|
+
}
|
package/stdlib/env.arc
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Arc Standard Library: env module
|
|
2
|
+
# Environment variable utilities
|
|
3
|
+
|
|
4
|
+
pub fn get(key) => __native("env.get", key)
|
|
5
|
+
pub fn get_or(key, default) => __native("env.get_or", key, default)
|
|
6
|
+
pub fn set(key, val) => __native("env.set", key, val)
|
|
7
|
+
pub fn remove(key) => __native("env.remove", key)
|
|
8
|
+
pub fn has(key) => __native("env.has", key)
|
|
9
|
+
pub fn list() => __native("env.list")
|
|
10
|
+
pub fn require(key) => __native("env.require", key)
|
package/stdlib/error.arc
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Arc Standard Library: error module
|
|
2
|
+
# Structured error handling
|
|
3
|
+
|
|
4
|
+
# Create a structured error
|
|
5
|
+
pub fn error(code, message) => error_new(code, message)
|
|
6
|
+
|
|
7
|
+
# Check if a value is an error
|
|
8
|
+
pub fn is_error(value) => error_is_error(value)
|
|
9
|
+
|
|
10
|
+
# Wrap an error with additional context
|
|
11
|
+
pub fn wrap_error(err, context) => error_wrap(err, context)
|
|
12
|
+
|
|
13
|
+
# Try executing a function, return Ok/Err result
|
|
14
|
+
pub fn try_fn(f) => error_try(f)
|
|
15
|
+
|
|
16
|
+
# Execute fn, call handler if result is an error
|
|
17
|
+
pub fn try_catch(f, handler) {
|
|
18
|
+
let result = f()
|
|
19
|
+
if is_error(result) { handler(result) }
|
|
20
|
+
el { result }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Execute fn, always run cleanup
|
|
24
|
+
pub fn try_finally(f, cleanup) {
|
|
25
|
+
let result = f()
|
|
26
|
+
cleanup()
|
|
27
|
+
result
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Full try/catch/finally
|
|
31
|
+
pub fn try_catch_finally(f, handler, cleanup) {
|
|
32
|
+
let result = f()
|
|
33
|
+
let handled = if is_error(result) { handler(result) } el { result }
|
|
34
|
+
cleanup()
|
|
35
|
+
handled
|
|
36
|
+
}
|
package/stdlib/html.arc
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Arc Standard Library: html module
|
|
2
|
+
# HTML parsing and generation utilities
|
|
3
|
+
|
|
4
|
+
pub fn parse(s) {
|
|
5
|
+
__native("html.parse", s)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
pub fn select(node, selector) {
|
|
9
|
+
__native("html.select", node, selector)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
pub fn text(node) {
|
|
13
|
+
__native("html.text", node)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub fn attr(node, name) {
|
|
17
|
+
__native("html.attr", node, name)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub fn create(tag, attrs, children) {
|
|
21
|
+
let node = {}
|
|
22
|
+
node["tag"] = tag
|
|
23
|
+
node["attrs"] = attrs
|
|
24
|
+
node["children"] = children
|
|
25
|
+
node
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn render(node) {
|
|
29
|
+
__native("html.render", node)
|
|
30
|
+
}
|
package/stdlib/http.arc
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Arc Standard Library: http module
|
|
2
|
+
# HTTP utilities built on @ tool calls
|
|
3
|
+
|
|
4
|
+
pub fn get(url) => @GET url
|
|
5
|
+
|
|
6
|
+
pub fn post(url, body) {
|
|
7
|
+
@POST url {data: body}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
pub fn put(url, body) {
|
|
11
|
+
@PUT url {data: body}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pub fn delete(url) => @DELETE url
|
|
15
|
+
|
|
16
|
+
pub fn fetch_all(urls) {
|
|
17
|
+
map(urls, u => @GET u)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub fn parse_url(url) {
|
|
21
|
+
# Extract protocol, host, path from URL string
|
|
22
|
+
let mut protocol = ""
|
|
23
|
+
let mut rest = url
|
|
24
|
+
|
|
25
|
+
if starts(url, "https://") {
|
|
26
|
+
protocol = "https"
|
|
27
|
+
rest = slice(url, 8, len(url))
|
|
28
|
+
} el if starts(url, "http://") {
|
|
29
|
+
protocol = "http"
|
|
30
|
+
rest = slice(url, 7, len(url))
|
|
31
|
+
} el {
|
|
32
|
+
protocol = ""
|
|
33
|
+
rest = url
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Find first / after protocol
|
|
37
|
+
let parts = split(rest, "/")
|
|
38
|
+
let host = head(parts)
|
|
39
|
+
let path_parts = tail(parts)
|
|
40
|
+
let path = if len(path_parts) > 0 { "/" ++ join(path_parts, "/") } el { "/" }
|
|
41
|
+
|
|
42
|
+
{protocol: protocol, host: host, path: path}
|
|
43
|
+
}
|
package/stdlib/io.arc
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Arc Standard Library: io module
|
|
2
|
+
# File I/O utilities (operates on strings/lists; actual I/O via prelude read/write)
|
|
3
|
+
|
|
4
|
+
pub fn read_lines(path) {
|
|
5
|
+
let content = read(path)
|
|
6
|
+
if content == nil { [] }
|
|
7
|
+
el { split(content, "\n") }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
pub fn write_lines(path, lines) {
|
|
11
|
+
let content = join(lines, "\n")
|
|
12
|
+
write(path, content)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub fn exists(path) {
|
|
16
|
+
# Simulated: try reading, return true if non-nil
|
|
17
|
+
let content = read(path)
|
|
18
|
+
content != nil
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn append(path, data) {
|
|
22
|
+
let existing = read(path)
|
|
23
|
+
if existing == nil {
|
|
24
|
+
write(path, str(data))
|
|
25
|
+
} el {
|
|
26
|
+
write(path, existing ++ str(data))
|
|
27
|
+
}
|
|
28
|
+
}
|