syntastica_parsers_git/
lib.rs

1#![doc = include_str!("../README.md")]
2//!
3#![cfg_attr(
4    feature = "docs",
5    cfg_attr(doc, doc = ::document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#))
6)]
7#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
8#![warn(rust_2018_idioms)]
9#![deny(missing_docs)]
10
11syntastica_macros::parsers_ffi!();
12
13/// Basic implementation of some libc functions that tree-sitter parsers can link to.
14#[cfg(all(
15    feature = "runtime-c2rust",
16    target_arch = "wasm32",
17    target_vendor = "unknown",
18    target_os = "unknown",
19    target_env = ""
20))]
21#[allow(non_camel_case_types)]
22mod wasm_c_bridge {
23    use std::{
24        alloc::{GlobalAlloc, Layout, System},
25        collections::HashMap,
26        ffi::{c_void, CStr},
27        sync::{LazyLock, Mutex},
28    };
29
30    type wint_t = u32;
31    type size_t = usize;
32    type c_char = i8;
33    type int = i32;
34
35    /// <https://en.cppreference.com/w/c/program/abort>
36    #[no_mangle]
37    extern "C" fn abort() {
38        panic!("program aborted");
39    }
40
41    /// <https://en.cppreference.com/w/c/string/wide/towupper>
42    #[no_mangle]
43    extern "C" fn towupper(wc: wint_t) -> wint_t {
44        let Some(char) = char::from_u32(wc) else {
45            return wc;
46        };
47        let mut uppercase = char.to_uppercase();
48        if uppercase.len() == 1 {
49            uppercase.next().unwrap() as wint_t
50        } else {
51            wc
52        }
53    }
54
55    /// <https://en.cppreference.com/w/c/string/wide/towlower>
56    #[no_mangle]
57    extern "C" fn towlower(wc: wint_t) -> wint_t {
58        let Some(char) = char::from_u32(wc) else {
59            return wc;
60        };
61        let mut uppercase = char.to_lowercase();
62        if uppercase.len() == 1 {
63            uppercase.next().unwrap() as wint_t
64        } else {
65            wc
66        }
67    }
68
69    /// <https://en.cppreference.com/w/c/string/wide/iswalnum>
70    #[no_mangle]
71    extern "C" fn iswalnum(ch: wint_t) -> int {
72        char::from_u32(ch).is_some_and(|ch| ch.is_alphanumeric()) as int
73    }
74
75    /// <https://en.cppreference.com/w/c/string/wide/iswalpha>
76    #[no_mangle]
77    extern "C" fn iswalpha(ch: wint_t) -> int {
78        char::from_u32(ch).is_some_and(|ch| ch.is_alphabetic()) as int
79    }
80
81    /// <https://en.cppreference.com/w/c/string/wide/iswblank>
82    #[no_mangle]
83    extern "C" fn iswblank(ch: wint_t) -> int {
84        (ch == b' ' as wint_t || ch == b'\t' as wint_t) as int
85    }
86
87    /// <https://en.cppreference.com/w/c/string/wide/iswcntrl>
88    #[no_mangle]
89    extern "C" fn iswcntrl(ch: wint_t) -> int {
90        char::from_u32(ch).is_some_and(|ch| ch.is_control()) as int
91    }
92
93    /// <https://en.cppreference.com/w/c/string/wide/iswdigit>
94    #[no_mangle]
95    extern "C" fn iswdigit(ch: wint_t) -> int {
96        char::from_u32(ch).is_some_and(|ch| ch.is_numeric()) as int
97    }
98
99    /// <https://en.cppreference.com/w/c/string/wide/iswgraph>
100    #[no_mangle]
101    extern "C" fn iswgraph(ch: wint_t) -> int {
102        char::from_u32(ch).is_some_and(|ch| ch.is_ascii_graphic()) as int
103    }
104
105    /// <https://en.cppreference.com/w/c/string/wide/iswlower>
106    #[no_mangle]
107    extern "C" fn iswlower(ch: wint_t) -> int {
108        char::from_u32(ch).is_some_and(|ch| ch.is_lowercase()) as int
109    }
110
111    /// <https://en.cppreference.com/w/c/string/wide/iswprint>
112    #[no_mangle]
113    extern "C" fn iswprint(ch: wint_t) -> int {
114        char::from_u32(ch).is_some_and(|ch| ch.is_ascii_graphic() || ch == ' ') as int
115    }
116
117    /// <https://en.cppreference.com/w/c/string/wide/iswpunct>
118    #[no_mangle]
119    extern "C" fn iswpunct(ch: wint_t) -> int {
120        char::from_u32(ch).is_some_and(|ch| ch.is_ascii_punctuation()) as int
121    }
122
123    /// <https://en.cppreference.com/w/c/string/wide/iswspace>
124    #[no_mangle]
125    extern "C" fn iswspace(ch: wint_t) -> int {
126        char::from_u32(ch).is_some_and(|ch| ch.is_whitespace()) as int
127    }
128
129    /// <https://en.cppreference.com/w/c/string/wide/iswupper>
130    #[no_mangle]
131    extern "C" fn iswupper(ch: wint_t) -> int {
132        char::from_u32(ch).is_some_and(|ch| ch.is_uppercase()) as int
133    }
134
135    /// <https://en.cppreference.com/w/c/string/wide/iswxdigit>
136    #[no_mangle]
137    extern "C" fn iswxdigit(ch: wint_t) -> int {
138        char::from_u32(ch).is_some_and(|ch| ch.is_ascii_hexdigit()) as int
139    }
140
141    #[no_mangle]
142    unsafe extern "C" fn __assert2(
143        file: *const c_char,
144        line: int,
145        func: *const c_char,
146        error: *const c_char,
147    ) {
148        let file = CStr::from_ptr(file).to_string_lossy();
149        let func = CStr::from_ptr(func).to_string_lossy();
150        let error = CStr::from_ptr(error).to_string_lossy();
151        panic!("assertion failed in {file} on line {line} in {func}: {error}");
152    }
153
154    /// <https://en.cppreference.com/w/c/string/byte/strcmp>
155    #[no_mangle]
156    unsafe extern "C" fn strcmp(lhs: *const c_char, rhs: *const c_char) -> int {
157        let lhs = CStr::from_ptr(lhs);
158        let rhs = CStr::from_ptr(rhs);
159        lhs.cmp(rhs) as int
160    }
161
162    /// <https://en.cppreference.com/w/c/string/byte/strncpy>
163    #[no_mangle]
164    unsafe extern "C" fn strncpy(
165        dest: *mut c_char,
166        src: *const c_char,
167        count: size_t,
168    ) -> *mut c_char {
169        for i in 0..count {
170            let cp = src.add(i).read();
171            dest.add(i).write(cp)
172        }
173        dest
174    }
175
176    /// <https://en.cppreference.com/w/c/string/byte/memchr>
177    #[no_mangle]
178    unsafe extern "C" fn memchr(ptr: *const c_void, ch: int, count: size_t) -> *mut c_void {
179        let ptr = ptr as *const u8;
180        let ch = ch as u8;
181        for i in 0..count {
182            if ptr.add(i).read() == ch {
183                return ptr.add(i) as *mut _;
184            }
185        }
186        std::ptr::null_mut()
187    }
188
189    static LAYOUTS: LazyLock<Mutex<HashMap<usize, Layout>>> = LazyLock::new(Default::default);
190    const MIN_ALIGN: usize = 8;
191
192    /// <https://en.cppreference.com/w/c/memory/malloc>
193    #[no_mangle]
194    unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
195        let layout = Layout::from_size_align_unchecked(size, MIN_ALIGN);
196        let ptr = System.alloc(layout);
197        if !ptr.is_null() {
198            LAYOUTS.lock().unwrap().insert(ptr as usize, layout);
199        }
200        ptr as *mut _
201    }
202
203    /// <https://en.cppreference.com/w/c/memory/calloc>
204    #[no_mangle]
205    unsafe extern "C" fn calloc(num: size_t, size: size_t) -> *mut c_void {
206        let layout = Layout::from_size_align_unchecked(num * size, MIN_ALIGN);
207        let ptr = System.alloc_zeroed(layout);
208        if !ptr.is_null() {
209            LAYOUTS.lock().unwrap().insert(ptr as usize, layout);
210        }
211        ptr as *mut _
212    }
213
214    /// <https://en.cppreference.com/w/c/memory/realloc>
215    #[no_mangle]
216    unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: size_t) -> *mut c_void {
217        if ptr.is_null() {
218            return malloc(new_size);
219        }
220        let layout = *LAYOUTS
221            .lock()
222            .unwrap()
223            .get(&(ptr as usize))
224            .unwrap_unchecked();
225        let ptr = System.realloc(ptr as *mut _, layout, new_size);
226        if !ptr.is_null() {
227            LAYOUTS.lock().unwrap().insert(
228                ptr as usize,
229                Layout::from_size_align_unchecked(new_size, layout.align()),
230            );
231        }
232        ptr as *mut _
233    }
234
235    /// <https://en.cppreference.com/w/c/memory/free>
236    #[no_mangle]
237    unsafe extern "C" fn free(ptr: *mut c_void) {
238        if ptr.is_null() {
239            return;
240        }
241        let layout = LAYOUTS
242            .lock()
243            .unwrap()
244            .remove(&(ptr as usize))
245            .unwrap_unchecked();
246        System.dealloc(ptr as *mut _, layout);
247    }
248}