All incomplete examples have been updated and some corrections have been made to the parser to make them work. (0.37.17)
This commit is contained in:
parent
37c5ae6f58
commit
92aacff71a
41 changed files with 654 additions and 130 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
project(fun VERSION 0.37.15 LANGUAGES C)
|
project(fun VERSION 0.37.17 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,9 @@ boolean b = false
|
||||||
print("b => " + to_string(b))
|
print("b => " + to_string(b))
|
||||||
/* Try typeof via built-in function if available */
|
/* Try typeof via built-in function if available */
|
||||||
print("typeof(b) => " + typeof(b))
|
print("typeof(b) => " + typeof(b))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
b => false
|
||||||
|
typeof(b) => Boolean
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,25 @@ if f
|
||||||
print("if f: branch taken (unexpected)")
|
print("if f: branch taken (unexpected)")
|
||||||
else
|
else
|
||||||
print("if f: else branch taken")
|
print("if f: else branch taken")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
typeof(t) => Boolean
|
||||||
|
typeof(f) => Boolean
|
||||||
|
t literal => true
|
||||||
|
f literal => false
|
||||||
|
true && true => true
|
||||||
|
true && false => false
|
||||||
|
false || true => 1
|
||||||
|
false || false => 0
|
||||||
|
!true => false
|
||||||
|
!false => true
|
||||||
|
true == true => true
|
||||||
|
true != false => true
|
||||||
|
true == 1 => true
|
||||||
|
false == 0 => true
|
||||||
|
1 == true => true
|
||||||
|
0 != true => true
|
||||||
|
if t: branch taken
|
||||||
|
if f: else branch taken
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,26 @@ print(typeof(cast(42, "Function"))) // -> "Nil"
|
||||||
print(cast(cast("42", "Number"), "String")) // -> "42"
|
print(cast(cast("42", "Number"), "String")) // -> "42"
|
||||||
|
|
||||||
print("=== Done ===")
|
print("=== Done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== CAST demo ===
|
||||||
|
123
|
||||||
|
0
|
||||||
|
42
|
||||||
|
100
|
||||||
|
String
|
||||||
|
0
|
||||||
|
1
|
||||||
|
Array
|
||||||
|
1
|
||||||
|
42
|
||||||
|
String
|
||||||
|
0
|
||||||
|
Nil
|
||||||
|
Function
|
||||||
|
Nil
|
||||||
|
42
|
||||||
|
=== Done ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,8 @@ if ok == 1
|
||||||
print("Downloaded to " + path)
|
print("Downloaded to " + path)
|
||||||
else
|
else
|
||||||
print("Download failed")
|
print("Download failed")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Downloaded to ./downloaded.png
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,9 @@ print("Raw length: " + to_string(len(resp)))
|
||||||
obj = json_parse(resp)
|
obj = json_parse(resp)
|
||||||
if obj != nil
|
if obj != nil
|
||||||
print("Title: " + obj["slideshow"]["title"])
|
print("Title: " + obj["slideshow"]["title"])
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Raw length: 429
|
||||||
|
Title: Sample Slide Show
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,30 @@ if obj != nil
|
||||||
|
|
||||||
if obj != nil
|
if obj != nil
|
||||||
print("Origin: " + to_string(obj["origin"]))
|
print("Origin: " + to_string(obj["origin"]))
|
||||||
|
|
||||||
|
/* Possible output:
|
||||||
|
Response: {
|
||||||
|
"args": {},
|
||||||
|
"data": "",
|
||||||
|
"files": {},
|
||||||
|
"form": {
|
||||||
|
"lang": "fun",
|
||||||
|
"name": "Fun"
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Accept": "*/*",
|
||||||
|
"Content-Length": "17",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Host": "httpbin.org",
|
||||||
|
"X-Amzn-Trace-Id": "Root=1-6944834b-74f499e251c322713e7dd9a8"
|
||||||
|
},
|
||||||
|
"json": null,
|
||||||
|
"origin": "5.252.226.107",
|
||||||
|
"url": "https://httpbin.org/post"
|
||||||
|
}
|
||||||
|
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Host: httpbin.org
|
||||||
|
Origin: 5.252.226.107
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,7 @@ echo("Hello, ")
|
||||||
echo("world")
|
echo("world")
|
||||||
print("!")
|
print("!")
|
||||||
|
|
||||||
// Expected output:
|
/* Expected output:
|
||||||
// Hello, world!
|
Hello, world!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,3 +59,20 @@ print(a < b && n >= 10) // expect 1
|
||||||
print((a + b) == 5 && flag) // expect 1
|
print((a + b) == 5 && flag) // expect 1
|
||||||
|
|
||||||
print("=== Expressions test end ===")
|
print("=== Expressions test end ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== Expressions test start ===
|
||||||
|
16
|
||||||
|
10
|
||||||
|
-10
|
||||||
|
1
|
||||||
|
true
|
||||||
|
false
|
||||||
|
true
|
||||||
|
1
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
=== Expressions test end ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ for x in range(1, 3)
|
||||||
|
|
||||||
print("=== for/range test end ===")
|
print("=== for/range test end ===")
|
||||||
|
|
||||||
/*
|
/* Expected output:
|
||||||
=== for/range test start ===
|
=== for/range test start ===
|
||||||
0
|
0
|
||||||
1
|
1
|
||||||
|
|
@ -112,3 +112,4 @@ print("=== for/range test end ===")
|
||||||
4
|
4
|
||||||
=== for/range test end ===
|
=== for/range test end ===
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,3 +57,17 @@ number n = 5
|
||||||
print(add(n, 10)) // expect 15
|
print(add(n, 10)) // expect 15
|
||||||
|
|
||||||
print("=== Functions test end ===")
|
print("=== Functions test end ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== Functions test start ===
|
||||||
|
5
|
||||||
|
7
|
||||||
|
7
|
||||||
|
4
|
||||||
|
6
|
||||||
|
6
|
||||||
|
42
|
||||||
|
15
|
||||||
|
=== Functions test end ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
print("Have fun!")
|
print("Have fun!")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Have fun!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,13 @@ fun have_fun()
|
||||||
print(n)
|
print(n)
|
||||||
|
|
||||||
have_fun()
|
have_fun()
|
||||||
|
|
||||||
|
print("Have fun!")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Have fun!
|
||||||
|
Have fun!
|
||||||
|
10
|
||||||
|
Have fun!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,3 +41,12 @@ if (n >= 10)
|
||||||
print("answer") // expect: answer
|
print("answer") // expect: answer
|
||||||
|
|
||||||
print("=== if/else-if/else done ===")
|
print("=== if/else-if/else done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== if/else-if/else test ===
|
||||||
|
big
|
||||||
|
42
|
||||||
|
answer
|
||||||
|
=== if/else-if/else done ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,10 @@ number y = 32
|
||||||
|
|
||||||
print("add(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(add(x, y)))
|
print("add(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(add(x, y)))
|
||||||
print("times(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(times(x, y)))
|
print("times(" + to_string(x) + ", " + to_string(y) + ") = " + to_string(times(x, y)))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
== include lib demo ==
|
||||||
|
Hello from system lib!
|
||||||
|
add(10, 32) = 42
|
||||||
|
times(10, 32) = 320
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ print("sum(" + to_string(a) + ", " + to_string(b) + ") = " + to_string(sum(a, b)
|
||||||
// To include from the system library directory (/usr/lib/fun), use angle brackets:
|
// To include from the system library directory (/usr/lib/fun), use angle brackets:
|
||||||
// #include <some_lib.fun>
|
// #include <some_lib.fun>
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
== include local demo ==
|
||||||
|
Hello, Fun
|
||||||
|
sum(2, 3) = 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,3 +14,8 @@ fun greet(name)
|
||||||
|
|
||||||
fun sum(a, b)
|
fun sum(a, b)
|
||||||
return a + b
|
return a + b
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
None, it's a lib...
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,15 @@ ok = ini.save(nil)
|
||||||
print("saved=" + to_string(ok))
|
print("saved=" + to_string(ok))
|
||||||
|
|
||||||
ini.close()
|
ini.close()
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
[app]
|
||||||
|
name=FunApp
|
||||||
|
version=1.2.3
|
||||||
|
debug=1
|
||||||
|
[database]
|
||||||
|
host=localhost
|
||||||
|
port=5432
|
||||||
|
saved=1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,28 @@ else
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
ini_free(h)
|
ini_free(h)
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
[app]
|
||||||
|
name=FunApp
|
||||||
|
version=1.2.3
|
||||||
|
debug=1
|
||||||
|
[database]
|
||||||
|
host=localhost
|
||||||
|
port=5432
|
||||||
|
user=fun
|
||||||
|
pass=secret
|
||||||
|
pool_size=8
|
||||||
|
timeout=2.5
|
||||||
|
[network]
|
||||||
|
ssl=1
|
||||||
|
retries=3
|
||||||
|
base_url=https://api.example.com
|
||||||
|
[features]
|
||||||
|
feature_x=0
|
||||||
|
feature_y=0
|
||||||
|
[paths]
|
||||||
|
data_dir=./data
|
||||||
|
log_file=./logs/app.log
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,3 +28,9 @@ else
|
||||||
if ok
|
if ok
|
||||||
ini_save(h, path)
|
ini_save(h, path)
|
||||||
ini_free(h)
|
ini_free(h)
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
user=<EFBFBD><EFBFBD><EFBFBD><EFBFBD>U
|
||||||
|
retries=3
|
||||||
|
ssl=1
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,26 @@ else
|
||||||
print(" max_files=" + to_string(logs_max_files))
|
print(" max_files=" + to_string(logs_max_files))
|
||||||
|
|
||||||
ini_free(h)
|
ini_free(h)
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
[server]
|
||||||
|
host=example.org
|
||||||
|
port=8080
|
||||||
|
[server.tls]
|
||||||
|
enabled=1
|
||||||
|
version=1.3
|
||||||
|
ciphers=TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256
|
||||||
|
[users.admin]
|
||||||
|
name=alice
|
||||||
|
active=1
|
||||||
|
quota_gb=100
|
||||||
|
[users.guest]
|
||||||
|
name=bob
|
||||||
|
active=0
|
||||||
|
quota_gb=5
|
||||||
|
[paths.logs]
|
||||||
|
dir=./var/log/fun
|
||||||
|
rotate=1
|
||||||
|
max_files=7
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,45 @@ print(json.stringify(summary, 1))
|
||||||
out_path = "/tmp/fun_complex_out.json"
|
out_path = "/tmp/fun_complex_out.json"
|
||||||
ok = json.to_file(out_path, cfg, 1)
|
ok = json.to_file(out_path, cfg, 1)
|
||||||
print(ok) // 1 on success
|
print(ok) // 1 on success
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
-- JSON: parse from string and pretty print --
|
||||||
|
Dump:
|
||||||
|
{"name": Ada, "active": true, "score": 99.5, "count": 42, "tags": [C, Ada, Math], "extra": nil}
|
||||||
|
Ada
|
||||||
|
true
|
||||||
|
42
|
||||||
|
3
|
||||||
|
{
|
||||||
|
"name":"Ada",
|
||||||
|
"active":true,
|
||||||
|
"score":99.5,
|
||||||
|
"count":42,
|
||||||
|
"tags":[
|
||||||
|
"C",
|
||||||
|
"Ada",
|
||||||
|
"Math"
|
||||||
|
],
|
||||||
|
"extra":null
|
||||||
|
}
|
||||||
|
-- JSON: load from file, inspect, and save pretty to /tmp --
|
||||||
|
Dump:
|
||||||
|
nil
|
||||||
|
Dump:
|
||||||
|
{"project": {"name": Fun, "version": 0.27.2, "website": https://fun-lang.xyz, "license": {"name": Apache-2.0, "url": https://opensource.org/license/apache-2-0}}, "features": {"enabled": [arrays, maps, json, pcsc], "experimental": {"repl": true, "sockets": true, "odbc": false, "notes": nil}}, "users": [{"id": 1, "name": Ada, "roles": [admin, math], "active": true, "score": 99.5, "prefs": {"theme": dark, "editor": {"tabWidth": 2, "font": Fira Code}}}, {"id": 2, "name": Linus, "roles": [user, kernel], "active": false, "score": 88, "prefs": {"theme": light, "editor": {"tabWidth": 8, "font": Monospace}}}], "metrics": {"counters": [0, 1, 1, 2, 3, 5, 8], "latency_ms": {"p50": 1.23, "p90": 3.21, "p99": 12.34}, "builds": 1234567890123456789, "last_release_ts": 1732406400000}, "matrix": [[1, 2, 3], [4, 5, 6], [7, 8, 9]], "notes": UTF-8 ✓ – emojis: 🚀🔥, "null_field": nil}
|
||||||
|
Fun
|
||||||
|
0.27.2
|
||||||
|
2
|
||||||
|
{
|
||||||
|
"user_count":2,
|
||||||
|
"first_user_name":"Linus",
|
||||||
|
"features_enabled":[
|
||||||
|
"arrays",
|
||||||
|
"maps",
|
||||||
|
"json",
|
||||||
|
"pcsc"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
1
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,8 @@ class Greeter(string prefix)
|
||||||
// Methods must declare 'this' as the first parameter
|
// Methods must declare 'this' as the first parameter
|
||||||
fun say(this, name)
|
fun say(this, name)
|
||||||
print(this.prefix + " " + to_string(name))
|
print(this.prefix + " " + to_string(name))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
None, it's a lib.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,3 +25,11 @@ fun greet()
|
||||||
else
|
else
|
||||||
print("Hello, " + user + "!")
|
print("Hello, " + user + "!")
|
||||||
greet()
|
greet()
|
||||||
|
|
||||||
|
/* Possible output:
|
||||||
|
HOME=/home/hanez
|
||||||
|
SHELL=/bin/zsh
|
||||||
|
FUN_NOT_SET=
|
||||||
|
Hello, hanez!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,3 +138,77 @@ for g in pcre2_findall(greedy, ng_text, OR(flags, 4)) // DOTALL ensures '.' cov
|
||||||
print("Non-greedy:")
|
print("Non-greedy:")
|
||||||
for l in pcre2_findall(lazy, ng_text, OR(flags, 4))
|
for l in pcre2_findall(lazy, ng_text, OR(flags, 4))
|
||||||
print(l["full"])
|
print(l["full"])
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
-- PCRE2 builtins (no class) --
|
||||||
|
test:
|
||||||
|
1
|
||||||
|
first full:
|
||||||
|
Hello
|
||||||
|
span:
|
||||||
|
0
|
||||||
|
..
|
||||||
|
5
|
||||||
|
groups count:
|
||||||
|
1
|
||||||
|
all:
|
||||||
|
Hello
|
||||||
|
@
|
||||||
|
0
|
||||||
|
..
|
||||||
|
5
|
||||||
|
all:
|
||||||
|
123
|
||||||
|
@
|
||||||
|
6
|
||||||
|
..
|
||||||
|
9
|
||||||
|
all:
|
||||||
|
world
|
||||||
|
@
|
||||||
|
10
|
||||||
|
..
|
||||||
|
15
|
||||||
|
|
||||||
|
-- More regex demos --
|
||||||
|
Emails (findall):
|
||||||
|
one@example.com
|
||||||
|
Two@Example.COM
|
||||||
|
URLs:
|
||||||
|
IPv4:
|
||||||
|
8.8.8.8
|
||||||
|
192.168.0.1
|
||||||
|
Dates (with groups Y/M/D):
|
||||||
|
1999-12-31
|
||||||
|
1999/12/31
|
||||||
|
2025-11-25
|
||||||
|
2025/11/25
|
||||||
|
Hex colors:
|
||||||
|
#FF00FF
|
||||||
|
#1a2b3c
|
||||||
|
Quoted strings (with escapes):
|
||||||
|
"hi there"
|
||||||
|
"indented"
|
||||||
|
"quote\"inside"
|
||||||
|
Multiline ^ anchors (first token of each line):
|
||||||
|
first
|
||||||
|
Second
|
||||||
|
third
|
||||||
|
Dotall OFF (should fail):
|
||||||
|
0
|
||||||
|
Dotall ON (should match):
|
||||||
|
1
|
||||||
|
Word boundary, case-insensitive:
|
||||||
|
The
|
||||||
|
the
|
||||||
|
THE
|
||||||
|
Lookahead (word before number):
|
||||||
|
foo
|
||||||
|
baz
|
||||||
|
Greedy:
|
||||||
|
<a>one</a><a>two</a>
|
||||||
|
Non-greedy:
|
||||||
|
<a>one</a>
|
||||||
|
<a>two</a>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,5 @@ SHA-1('abc') = e6cd2bcee460c45d41565ac877d866a159a16e19
|
||||||
SHA-1(616263 hex) = e6cd2bcee460c45d41565ac877d866a159a16e19
|
SHA-1(616263 hex) = e6cd2bcee460c45d41565ac877d866a159a16e19
|
||||||
SHA-1('') = da39a3ee5e6b4b0d3255bfef95601890afd80709
|
SHA-1('') = da39a3ee5e6b4b0d3255bfef95601890afd80709
|
||||||
=== done ===
|
=== done ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ print(s.sha384_hex("616263"))
|
||||||
|
|
||||||
// Raw string input
|
// Raw string input
|
||||||
print(s.sha384_str("abc"))
|
print(s.sha384_str("abc"))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
|
||||||
|
cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,3 +43,15 @@ else
|
||||||
print(0)
|
print(0)
|
||||||
|
|
||||||
print("=== end ===")
|
print("=== end ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== short-circuit demo ===
|
||||||
|
1
|
||||||
|
0
|
||||||
|
OR-NEEDED
|
||||||
|
1
|
||||||
|
AND-NEEDED
|
||||||
|
1
|
||||||
|
=== end ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,3 +42,16 @@ if (a != "")
|
||||||
print("a is non-empty")
|
print("a is non-empty")
|
||||||
|
|
||||||
print("=== strings test end ===")
|
print("=== strings test end ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== strings test start ===
|
||||||
|
Hello, World!
|
||||||
|
Hi there
|
||||||
|
x
|
||||||
|
x
|
||||||
|
Hello, Fun
|
||||||
|
Hi, Hello, You
|
||||||
|
a is non-empty
|
||||||
|
=== strings test end ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,3 +32,21 @@ else
|
||||||
data = sock_recv(fd, 8192)
|
data = sock_recv(fd, 8192)
|
||||||
print(data)
|
print(data)
|
||||||
sock_close(fd)
|
sock_close(fd)
|
||||||
|
|
||||||
|
/* Possible output:
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Thu, 18 Dec 2025 23:05:52 GMT
|
||||||
|
Content-Type: text/html
|
||||||
|
Connection: close
|
||||||
|
Vary: accept-encoding
|
||||||
|
Server: cloudflare
|
||||||
|
Last-Modified: Wed, 17 Dec 2025 03:51:06 GMT
|
||||||
|
Accept-Ranges: bytes
|
||||||
|
Cache-Control: max-age=14400
|
||||||
|
cf-cache-status: REVALIDATED
|
||||||
|
CF-RAY: 9b024eb71d91e51d-TXL
|
||||||
|
|
||||||
|
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,22 @@ else
|
||||||
resp = c.recv_all(8192)
|
resp = c.recv_all(8192)
|
||||||
print(resp)
|
print(resp)
|
||||||
c.close()
|
c.close()
|
||||||
|
|
||||||
|
/* Possible output:
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Date: Thu, 18 Dec 2025 23:06:52 GMT
|
||||||
|
Content-Type: text/html
|
||||||
|
Connection: close
|
||||||
|
Vary: accept-encoding
|
||||||
|
Server: cloudflare
|
||||||
|
Last-Modified: Wed, 17 Dec 2025 03:51:06 GMT
|
||||||
|
Accept-Ranges: bytes
|
||||||
|
Age: 59
|
||||||
|
Cache-Control: max-age=14400
|
||||||
|
cf-cache-status: HIT
|
||||||
|
CF-RAY: 9b02502e3f993237-TXL
|
||||||
|
|
||||||
|
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,8 @@ tk.pack("ok")
|
||||||
|
|
||||||
// Enter GUI loop (no-op if built without FUN_WITH_TCLTK)
|
// Enter GUI loop (no-op if built without FUN_WITH_TCLTK)
|
||||||
tk.loop()
|
tk.loop()
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
A GUI... ;)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,10 @@ catch err
|
||||||
finally
|
finally
|
||||||
print("finally always runs (syntactically)")
|
print("finally always runs (syntactically)")
|
||||||
print("after try")
|
print("after try")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
before try
|
||||||
|
inside try body
|
||||||
|
after try
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,32 @@ print(typeof(nn)) // -> "Nil"
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("Done. Uncomment lines above to see type errors in action.")
|
print("Done. Uncomment lines above to see type errors in action.")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
== Dynamic variable (untyped) ==
|
||||||
|
Number
|
||||||
|
100
|
||||||
|
String
|
||||||
|
hello
|
||||||
|
|
||||||
|
== Typed variables remain type-stable ==
|
||||||
|
String
|
||||||
|
hello
|
||||||
|
Number
|
||||||
|
0
|
||||||
|
0
|
||||||
|
Sint64
|
||||||
|
456
|
||||||
|
|
||||||
|
== Integer width clamping ==
|
||||||
|
-126
|
||||||
|
56
|
||||||
|
255
|
||||||
|
44
|
||||||
|
|
||||||
|
== Nil-typed variables must stay Nil ==
|
||||||
|
Nil
|
||||||
|
|
||||||
|
Done. Uncomment lines above to see type errors in action.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,12 @@ print("Now trying to assign a number to a string variable...")
|
||||||
s = 42 // Runtime TypeError: expected String (assignment rejected)
|
s = 42 // Runtime TypeError: expected String (assignment rejected)
|
||||||
|
|
||||||
print("This line will not execute due to the type error")
|
print("This line will not execute due to the type error")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
Reassigning typed variables to another type should fail
|
||||||
|
String
|
||||||
|
hello
|
||||||
|
Now trying to assign a number to a string variable...
|
||||||
|
TypeError: expected String
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,24 @@ print("ui8 value = " + to_string(ui8) + ", typeof(ui8) = " + typeof(ui8)) // Uin
|
||||||
|
|
||||||
si8 = si8 - 5
|
si8 = si8 - 5
|
||||||
print("si8 value = " + to_string(si8) + ", typeof(si8) = " + typeof(si8)) // Sint8
|
print("si8 value = " + to_string(si8) + ", typeof(si8) = " + typeof(si8)) // Sint8
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
typeof(si8) = Sint8
|
||||||
|
typeof(si16) = Sint16
|
||||||
|
typeof(si32) = Sint32
|
||||||
|
typeof(si64) = Sint64
|
||||||
|
typeof(ui8) = Uint8
|
||||||
|
typeof(ui16) = Uint16
|
||||||
|
typeof(ui32) = Uint32
|
||||||
|
typeof(ui64) = Uint64
|
||||||
|
typeof(n) = Sint64
|
||||||
|
typeof(s) = String
|
||||||
|
typeof(arr) = Array
|
||||||
|
typeof(m) = Map
|
||||||
|
typeof(f) = Function
|
||||||
|
typeof(x) = Nil
|
||||||
|
typeof(ui8 + 1) = Number
|
||||||
|
typeof(si16 - 2) = Number
|
||||||
|
ui8 value = 9, typeof(ui8) = Uint8
|
||||||
|
si8 value = -6, typeof(si8) = Sint8
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -73,3 +73,32 @@ print("pt['y'] = " + to_string(pt["y"]) + " :: " + typeof(pt["y"]))
|
||||||
// Conversions
|
// Conversions
|
||||||
print("to_string(123) => " + to_string(123))
|
print("to_string(123) => " + to_string(123))
|
||||||
print("to_number(\"456\") => " + to_string(to_number("456")))
|
print("to_number(\"456\") => " + to_string(to_number("456")))
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
a = 42 :: Sint64
|
||||||
|
b = -7 :: Sint64
|
||||||
|
zero = 0 :: Sint64
|
||||||
|
sum (a + b) = 35
|
||||||
|
diff (a - b) = 49
|
||||||
|
prod (a * 3) = 126
|
||||||
|
quot (a / 2) = 21
|
||||||
|
rem (a % 5) = 2
|
||||||
|
a > b = 1
|
||||||
|
a >= b = 1
|
||||||
|
a < b = 0
|
||||||
|
a <= b = 0
|
||||||
|
a == b = false
|
||||||
|
a != b = true
|
||||||
|
t = true :: Boolean
|
||||||
|
f = false :: Boolean
|
||||||
|
t && (a > 0) = true
|
||||||
|
f || (a < 0) = 0
|
||||||
|
sum 1..5 = 15
|
||||||
|
nums length = 5
|
||||||
|
nums[2] = 3
|
||||||
|
pt['x'] = 10 :: Number
|
||||||
|
pt['y'] = -3 :: Number
|
||||||
|
to_string(123) => 123
|
||||||
|
to_number("456") => 456
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,45 @@ print(typeof(p)) // -> "Class"
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("=== Done ===")
|
print("=== Done ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== Dynamic (untyped) ===
|
||||||
|
Number
|
||||||
|
String
|
||||||
|
|
||||||
|
=== Numbers and integer subtypes ===
|
||||||
|
Sint64
|
||||||
|
42
|
||||||
|
-126
|
||||||
|
4464
|
||||||
|
255
|
||||||
|
0
|
||||||
|
|
||||||
|
=== Strings ===
|
||||||
|
String
|
||||||
|
hello
|
||||||
|
|
||||||
|
=== Nil ===
|
||||||
|
Nil
|
||||||
|
nil
|
||||||
|
|
||||||
|
=== Arrays ===
|
||||||
|
Array
|
||||||
|
3
|
||||||
|
2
|
||||||
|
[1, 2]
|
||||||
|
|
||||||
|
=== Maps ===
|
||||||
|
Map
|
||||||
|
v
|
||||||
|
|
||||||
|
=== Functions ===
|
||||||
|
Function
|
||||||
|
12
|
||||||
|
|
||||||
|
=== Classes and Class-typed variables ===
|
||||||
|
Class
|
||||||
|
|
||||||
|
=== Done ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,3 +42,21 @@ fun countdown(n)
|
||||||
print(countdown(3)) // expect: 3,2,1 then 0
|
print(countdown(3)) // expect: 3,2,1 then 0
|
||||||
|
|
||||||
print("=== while test end ===")
|
print("=== while test end ===")
|
||||||
|
|
||||||
|
/* Expected output:
|
||||||
|
=== while test start ===
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
3
|
||||||
|
99
|
||||||
|
1
|
||||||
|
3
|
||||||
|
2
|
||||||
|
1
|
||||||
|
0
|
||||||
|
=== while test end ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
122
src/parser.c
122
src/parser.c
|
|
@ -568,19 +568,35 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
||||||
}
|
}
|
||||||
if (strcmp(name, "typeof") == 0) {
|
if (strcmp(name, "typeof") == 0) {
|
||||||
(*pos)++; /* '(' */
|
(*pos)++; /* '(' */
|
||||||
/* Disable compile-time shortcut for typeof(<identifier>); always evaluate at runtime */
|
/* Special handling for typeof(<identifier>) to return declared subtype for integers */
|
||||||
size_t peek = *pos;
|
size_t peek = *pos;
|
||||||
char *vname = NULL;
|
char *vname = NULL;
|
||||||
int handled = 0;
|
int handled = 0;
|
||||||
if (read_identifier_into(src, len, &peek, &vname)) {
|
if (read_identifier_into(src, len, &peek, &vname)) {
|
||||||
/* allow spaces before ')' */
|
|
||||||
skip_spaces(src, len, &peek);
|
skip_spaces(src, len, &peek);
|
||||||
if (peek < len && src[peek] == ')') {
|
if (peek < len && src[peek] == ')') {
|
||||||
/* Fall back to runtime evaluation path */
|
int meta = 0;
|
||||||
|
int lidx = local_find(vname);
|
||||||
|
if (lidx >= 0) {
|
||||||
|
meta = g_locals->types[lidx];
|
||||||
|
} else {
|
||||||
|
int gi = sym_index(vname);
|
||||||
|
if (gi >= 0) meta = G.types[gi];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta != 0 && meta != TYPE_META_STRING && meta != TYPE_META_BOOLEAN && meta != TYPE_META_NIL && meta != TYPE_META_CLASS && meta != TYPE_META_FLOAT) {
|
||||||
|
/* Integer subtype: ±bits */
|
||||||
|
int abs_bits = meta < 0 ? -meta : meta;
|
||||||
|
const char *tname = (meta < 0)
|
||||||
|
? (abs_bits==64? "Sint64" : (abs_bits==32? "Sint32" : (abs_bits==16? "Sint16" : "Sint8")))
|
||||||
|
: (abs_bits==64? "Uint64" : (abs_bits==32? "Uint32" : (abs_bits==16? "Uint16" : "Uint8")));
|
||||||
|
int ci = bytecode_add_constant(bc, make_string(tname));
|
||||||
|
bytecode_add_instruction(bc, OP_LOAD_CONST, ci);
|
||||||
|
*pos = peek + 1; /* consume name and ')' */
|
||||||
|
handled = 1;
|
||||||
|
}
|
||||||
free(vname);
|
free(vname);
|
||||||
/* handled remains 0 so we go to general-case below */
|
|
||||||
} else {
|
} else {
|
||||||
/* not a simple identifier-only typeof */
|
|
||||||
free(vname);
|
free(vname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -628,6 +644,7 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
||||||
int ciMap2 = bytecode_add_constant(bc, make_string("Map"));
|
int ciMap2 = bytecode_add_constant(bc, make_string("Map"));
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMap2); /* ["Map"] */
|
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMap2); /* ["Map"] */
|
||||||
}
|
}
|
||||||
|
int j_end2 = bytecode_add_instruction(bc, OP_JUMP, 0);
|
||||||
int after_map = bc->instr_count;
|
int after_map = bc->instr_count;
|
||||||
|
|
||||||
/* not map: compute typeof(v) */
|
/* not map: compute typeof(v) */
|
||||||
|
|
@ -636,6 +653,7 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos)
|
||||||
|
|
||||||
/* end */
|
/* end */
|
||||||
bytecode_set_operand(bc, j_end, bc->instr_count);
|
bytecode_set_operand(bc, j_end, bc->instr_count);
|
||||||
|
bytecode_set_operand(bc, j_end2, bc->instr_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
|
|
@ -2758,53 +2776,9 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
|
||||||
}
|
}
|
||||||
bytecode_set_operand(bc, j_skip_err, bc->instr_count);
|
bytecode_set_operand(bc, j_skip_err, bc->instr_count);
|
||||||
|
|
||||||
/* range check instead of clamp */
|
if (abs_bits > 0) {
|
||||||
int64_t minV = 0, maxV = 0;
|
bytecode_add_instruction(bc, (decl_bits < 0) ? OP_SCLAMP : OP_UCLAMP, abs_bits);
|
||||||
if (decl_bits < 0) {
|
|
||||||
/* signed */
|
|
||||||
if (abs_bits >= 64) { minV = INT64_MIN; maxV = INT64_MAX; }
|
|
||||||
else { maxV = (1LL << (abs_bits - 1)) - 1; minV = - (1LL << (abs_bits - 1)); }
|
|
||||||
} else {
|
|
||||||
/* unsigned */
|
|
||||||
if (abs_bits >= 63) { minV = 0; maxV = INT64_MAX; }
|
|
||||||
else { minV = 0; maxV = (1LL << abs_bits) - 1; }
|
|
||||||
}
|
}
|
||||||
int ciMin = bytecode_add_constant(bc, make_int(minV));
|
|
||||||
int ciMax = bytecode_add_constant(bc, make_int(maxV));
|
|
||||||
|
|
||||||
/* if (v < min) -> error */
|
|
||||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMin);
|
|
||||||
bytecode_add_instruction(bc, OP_LT, 0);
|
|
||||||
int j_after_min = bytecode_add_instruction(bc, OP_JUMP_IF_FALSE, 0);
|
|
||||||
{
|
|
||||||
const char *tname = (decl_bits < 0)
|
|
||||||
? (abs_bits==64? "int64" : (abs_bits==32? "int32" : (abs_bits==16? "int16" : "int8")))
|
|
||||||
: (abs_bits==64? "uint64" : (abs_bits==32? "uint32" : (abs_bits==16? "uint16" : "uint8")));
|
|
||||||
char buf[128];
|
|
||||||
snprintf(buf, sizeof(buf), "OverflowError: value out of range for %s", tname);
|
|
||||||
int ciMsg = bytecode_add_constant(bc, make_string(buf));
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMsg);
|
|
||||||
bytecode_add_instruction(bc, OP_THROW, 0);
|
|
||||||
}
|
|
||||||
bytecode_set_operand(bc, j_after_min, bc->instr_count);
|
|
||||||
|
|
||||||
/* if (v > max) -> error */
|
|
||||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMax);
|
|
||||||
bytecode_add_instruction(bc, OP_GT, 0);
|
|
||||||
int j_after_max = bytecode_add_instruction(bc, OP_JUMP_IF_FALSE, 0);
|
|
||||||
{
|
|
||||||
const char *tname = (decl_bits < 0)
|
|
||||||
? (abs_bits==64? "int64" : (abs_bits==32? "int32" : (abs_bits==16? "int16" : "int8")))
|
|
||||||
: (abs_bits==64? "uint64" : (abs_bits==32? "uint32" : (abs_bits==16? "uint16" : "uint8")));
|
|
||||||
char buf[128];
|
|
||||||
snprintf(buf, sizeof(buf), "OverflowError: value out of range for %s", tname);
|
|
||||||
int ciMsg = bytecode_add_constant(bc, make_string(buf));
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMsg);
|
|
||||||
bytecode_add_instruction(bc, OP_THROW, 0);
|
|
||||||
}
|
|
||||||
bytecode_set_operand(bc, j_after_max, bc->instr_count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3147,50 +3121,10 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si
|
||||||
}
|
}
|
||||||
bytecode_set_operand(bc, j_skip_err, bc->instr_count);
|
bytecode_set_operand(bc, j_skip_err, bc->instr_count);
|
||||||
|
|
||||||
/* range check instead of clamp */
|
if (abs_bits > 0) {
|
||||||
int64_t minV = 0, maxV = 0;
|
bytecode_add_instruction(bc, (meta < 0) ? OP_SCLAMP : OP_UCLAMP, abs_bits);
|
||||||
if (meta < 0) {
|
}
|
||||||
if (abs_bits >= 64) { minV = INT64_MIN; maxV = INT64_MAX; }
|
|
||||||
else { maxV = (1LL << (abs_bits - 1)) - 1; minV = - (1LL << (abs_bits - 1)); }
|
|
||||||
} else {
|
|
||||||
if (abs_bits >= 63) { minV = 0; maxV = INT64_MAX; }
|
|
||||||
else { minV = 0; maxV = (1LL << abs_bits) - 1; }
|
|
||||||
}
|
}
|
||||||
int ciMin = bytecode_add_constant(bc, make_int(minV));
|
|
||||||
int ciMax = bytecode_add_constant(bc, make_int(maxV));
|
|
||||||
|
|
||||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMin);
|
|
||||||
bytecode_add_instruction(bc, OP_LT, 0);
|
|
||||||
int j_after_min = bytecode_add_instruction(bc, OP_JUMP_IF_FALSE, 0);
|
|
||||||
{
|
|
||||||
const char *tname = (meta < 0)
|
|
||||||
? (abs_bits==64? "int64" : (abs_bits==32? "int32" : (abs_bits==16? "int16" : "int8")))
|
|
||||||
: (abs_bits==64? "uint64" : (abs_bits==32? "uint32" : (abs_bits==16? "uint16" : "uint8")));
|
|
||||||
char buf[128];
|
|
||||||
snprintf(buf, sizeof(buf), "OverflowError: value out of range for %s", tname);
|
|
||||||
int ciMsg2 = bytecode_add_constant(bc, make_string(buf));
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMsg2);
|
|
||||||
bytecode_add_instruction(bc, OP_THROW, 0);
|
|
||||||
}
|
|
||||||
bytecode_set_operand(bc, j_after_min, bc->instr_count);
|
|
||||||
|
|
||||||
bytecode_add_instruction(bc, OP_DUP, 0);
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMax);
|
|
||||||
bytecode_add_instruction(bc, OP_GT, 0);
|
|
||||||
int j_after_max = bytecode_add_instruction(bc, OP_JUMP_IF_FALSE, 0);
|
|
||||||
{
|
|
||||||
const char *tname = (meta < 0)
|
|
||||||
? (abs_bits==64? "int64" : (abs_bits==32? "int32" : (abs_bits==16? "int16" : "int8")))
|
|
||||||
: (abs_bits==64? "uint64" : (abs_bits==32? "uint32" : (abs_bits==16? "uint16" : "uint8")));
|
|
||||||
char buf[128];
|
|
||||||
snprintf(buf, sizeof(buf), "OverflowError: value out of range for %s", tname);
|
|
||||||
int ciMsg3 = bytecode_add_constant(bc, make_string(buf));
|
|
||||||
bytecode_add_instruction(bc, OP_LOAD_CONST, ciMsg3);
|
|
||||||
bytecode_add_instruction(bc, OP_THROW, 0);
|
|
||||||
}
|
|
||||||
bytecode_set_operand(bc, j_after_max, bc->instr_count);
|
|
||||||
}
|
|
||||||
/* dynamic (meta==0): no enforcement */
|
/* dynamic (meta==0): no enforcement */
|
||||||
|
|
||||||
if (lidx >= 0) {
|
if (lidx >= 0) {
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ static int read_identifier_into(const char *src, size_t len, size_t *pos, char *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t parse_int_literal_value(const char *src, size_t len, size_t *pos, int *ok) {
|
static uint64_t parse_int_literal_value(const char *src, size_t len, size_t *pos, int *ok) {
|
||||||
size_t p = *pos;
|
size_t p = *pos;
|
||||||
skip_spaces(src, len, &p);
|
skip_spaces(src, len, &p);
|
||||||
int sign = 1;
|
int sign = 1;
|
||||||
|
|
@ -173,31 +173,31 @@ static int64_t parse_int_literal_value(const char *src, size_t len, size_t *pos,
|
||||||
if ((p + 1) < len && src[p] == '0' && (src[p + 1] == 'x' || src[p + 1] == 'X')) {
|
if ((p + 1) < len && src[p] == '0' && (src[p + 1] == 'x' || src[p + 1] == 'X')) {
|
||||||
p += 2;
|
p += 2;
|
||||||
if (p >= len || !isxdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
if (p >= len || !isxdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
||||||
int64_t val = 0;
|
uint64_t val = 0;
|
||||||
while (p < len && isxdigit((unsigned char)src[p])) {
|
while (p < len && isxdigit((unsigned char)src[p])) {
|
||||||
char c = src[p];
|
char c = src[p];
|
||||||
int d = (c >= '0' && c <= '9') ? (c - '0')
|
int d = (c >= '0' && c <= '9') ? (c - '0')
|
||||||
: (c >= 'a' && c <= 'f') ? (c - 'a' + 10)
|
: (c >= 'a' && c <= 'f') ? (c - 'a' + 10)
|
||||||
: (c >= 'A' && c <= 'F') ? (c - 'A' + 10)
|
: (c >= 'A' && c <= 'F') ? (c - 'A' + 10)
|
||||||
: 0;
|
: 0;
|
||||||
val = (val << 4) + d;
|
val = (val << 4) + (uint64_t)d;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
*pos = p;
|
*pos = p;
|
||||||
*ok = 1;
|
*ok = 1;
|
||||||
return sign * val;
|
return (uint64_t)((int64_t)sign * (int64_t)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decimal fallback */
|
/* Decimal fallback */
|
||||||
if (!isdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
if (!isdigit((unsigned char)src[p])) { *ok = 0; return 0; }
|
||||||
int64_t val = 0;
|
uint64_t val = 0;
|
||||||
while (p < len && isdigit((unsigned char)src[p])) {
|
while (p < len && isdigit((unsigned char)src[p])) {
|
||||||
val = val * 10 + (src[p] - '0');
|
val = val * 10 + (uint64_t)(src[p] - '0');
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
*pos = p;
|
*pos = p;
|
||||||
*ok = 1;
|
*ok = 1;
|
||||||
return sign * val;
|
return (uint64_t)((int64_t)sign * (int64_t)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Include preprocessor ===
|
/* === Include preprocessor ===
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue