forked from ocen-lang/ocen
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmod.oc
More file actions
180 lines (152 loc) · 5.13 KB
/
Copy pathmod.oc
File metadata and controls
180 lines (152 loc) · 5.13 KB
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
import .libc
import .mem
import .variadic
@compiler c_embed "./prelude.h"
[extern] [exits] def exit(code: i32 = 0)
[extern "oc_trap"] def builtin_trap()
[exits]
def panic(msg: str = "<panic>") {
dump_backtrace()
eprintln("--------------------------------------------------------------------------------")
eprintln("%s", msg)
builtin_trap()
std::exit(1)
}
[extern "atoi"] def str::to_i32(this): i32
[extern "atof"] def str::to_f32(this): f32
def str::to_u32(this): u32 => this.to_i32() as u32 // FIXME: this doesn't always work
[extern "strlen"] def str::len(this): u32
[extern "strcat"] def str::concat(this, src: str)
[extern "strdup"] def str::copy(this): str
[operator "=="]
def str::eq(this, other: str): bool {
// Note: when doing `a == b`, it's also possible we want to compare pointers.
// We'll also do an explicit pointer comparison here to account for this, and
// only fall back to `strcmp` if the pointers are different.
let a = this as untyped_ptr
let b = other as untyped_ptr
if a == b return true
if not (a? and b?) return false
return libc::strcmp(this, other) == 0
}
// NOTE: The compiler relies on the name and signature of this function to generate
// format-strings. If you change this function, you'll need to update the compiler.
//
//! Create a formatted string.
def format(fmt: str, ...): str {
import ::variadic::{ VarArgs, vsnprintf }
let args: VarArgs
args.start(fmt)
let size = vsnprintf(null, 0, fmt, args);
args.end()
args.start(fmt)
let s = mem::alloc<char>((size + 1) as u32)
vsnprintf(s, size+1, fmt, args);
s[size] = '\0';
args.end()
return s;
}
def str::substring(this, start: u32, len: u32): str {
let new_str = mem::alloc<char>((len + 1) as u32)
libc::memcpy(new_str, &this[start], len)
return new_str
}
def str::ends_with(this, suffix: str): bool {
let suffix_len = suffix.len()
let len = .len()
if suffix_len > len {
return false
}
for let i = 0; i < suffix_len; i += 1 {
if this[len - suffix_len + i] != suffix[i] {
return false
}
}
return true
}
def str::starts_with(this, prefix: str): bool {
let prefix_len = prefix.len()
let len = .len()
if prefix_len > len {
return false
}
for let i = 0; i < prefix_len; i += 1 {
if this[i] != prefix[i] {
return false
}
}
return true
}
def str::strip_trailing_whitespace(this) {
for let i = .len() - 1; i >= 0; i -= 1 {
if this[i] != ' ' break
this[i] = '\0'
}
}
def str::remove_last_n(this, n: u32) {
this[.len() - n] = '\0'
}
def str::replace_with(&this, other: str) {
mem::free(*this)
*this = other
}
def str::free(&this) {
mem::free(*this)
*this = null
}
def str::chars(this, start: u32 = 0): CharIterator => CharIterator(this, this.len(), start)
struct CharIterator {
data: str
len: u32
pos: u32
}
def CharIterator::has_value(&this): bool => .pos < .len
def CharIterator::next(&this): u32 => .pos++
def CharIterator::cur(&this): char => .data[.pos]
def char::is_digit(this): bool => libc::isdigit(this)
def char::is_hex_digit(this): bool => libc::isxdigit(this)
def char::get_digit(this): u32 => this as u32 - '0' as u32
def char::value_from_hex(this): u8 {
if '0' <= this <= '9' return this as u8 - '0' as u8
if 'a' <= this <= 'f' return this as u8 - 'a' as u8 + 10
if 'A' <= this <= 'F' return this as u8 - 'A' as u8 + 10
panic(`[-] Invalid hex digit: '{this}' (0x{this:02x})`)
}
def char::hex_from_value(val: u8): char {
assert val < 16, f"Invalid value for hex char: {val}"
return "0123456789abcdef"[val]
}
// Deprecated: Backwards compatibility
def char::get_hex_digit(this): u8 => char::value_from_hex(this)
def char::is_alpha(this): bool => libc::isalpha(this)
def char::is_alnum(this): bool => libc::isalnum(this)
def char::is_print(this): bool => libc::isprint(this)
def char::is_space(this): bool => libc::isspace(this)
def char::is_upper(this): bool => libc::isupper(this)
def char::is_lower(this): bool => libc::islower(this)
def i32::min(this, b: i32): i32 => if this < b then this else b
def i32::max(this, b: i32): i32 => if this > b then this else b
def i8::min(this, b: i8): i8 => if this < b then this else b
def i8::max(this, b: i8): i8 => if this > b then this else b
def u64::min(this, other: u64): u64 => if this < other then this else other
def u64::max(this, other: u64): u64 => if this > other then this else other
def u32::min(this, other: u32): u32 => if this < other then this else other
def u32::max(this, other: u32): u32 => if this > other then this else other
def u8::min(this, other: u8): u8 => if this < other then this else other
def u8::max(this, other: u8): u8 => if this > other then this else other
//! Prints out a backtrace of the current stack to stdout
[extern] def dump_backtrace()
enum Endian {
Little
Big
}
def shift_args(argc: &i32, argv: &&str, where: str = "here"): str {
if *argc == 0 {
println(f"Expected argument but got none")
exit(1)
}
let arg = (*argv)[0]
(*argv) = (*argv) + 1
(*argc) = (*argc) - 1
return arg
}