1use proc_macro::TokenStream;
2
3use quote::{quote, quote_spanned};
4use regex::Regex;
5use syn::{LitStr, parse_macro_input};
6
7#[proc_macro]
8pub fn kind(token_stream: TokenStream) -> TokenStream {
9 let string_literal: LitStr = parse_macro_input!(token_stream);
10
11 let requested_kind = string_literal.value();
12
13 let language = tree_sitter_sus::language();
14 let found_id = language.id_for_node_kind(&requested_kind, true);
15
16 if found_id != 0 {
17 quote! {
18 #found_id
19 }
20 } else {
21 quote_spanned!(
22 string_literal.span() =>
23 compile_error!("This is not a valid node kind in the SUS language")
24 )
25 }
26 .into()
27}
28
29#[proc_macro]
30pub fn kw(token_stream: TokenStream) -> TokenStream {
31 let string_literal: LitStr = parse_macro_input!(token_stream);
32
33 let requested_keyword = string_literal.value();
34
35 let language = tree_sitter_sus::language();
36 let found_id = language.id_for_node_kind(&requested_keyword, false);
37
38 if found_id != 0 {
39 quote! {
40 #found_id
41 }
42 } else {
43 quote_spanned!(
44 string_literal.span() =>
45 compile_error!("This is not a valid keyword in the SUS language")
46 )
47 }
48 .into()
49}
50
51#[proc_macro]
52pub fn field(token_stream: TokenStream) -> TokenStream {
53 let string_literal: LitStr = parse_macro_input!(token_stream);
54
55 let requested_keyword = string_literal.value();
56
57 let language = tree_sitter_sus::language();
58 let found_id = language.field_id_for_name(&requested_keyword);
59
60 if let Some(found_id) = found_id {
61 let id_number: u16 = found_id.into();
62 quote! {
63 std::num::NonZeroU16::new(#id_number).unwrap()
64 }
65 } else {
66 quote_spanned!(
67 string_literal.span() =>
68 compile_error!("This is not a valid field in the SUS language")
69 )
70 }
71 .into()
72}
73
74#[proc_macro]
75pub fn get_builtin_type(token_stream: TokenStream) -> TokenStream {
76 let string_literal: LitStr = parse_macro_input!(token_stream);
77
78 let object_name = string_literal.value();
79
80 let core_file_text = std::fs::read_to_string("std/core.sus").unwrap();
81
82 let re = Regex::new(r"__builtin__\s+struct\s+([a-zA-Z0-9_]+)\s*(?:#\(.*\))?\s*\{").unwrap();
83
84 for (idx, c) in re.captures_iter(&core_file_text).enumerate() {
85 let (_full, [found_name]) = c.extract();
86 if found_name == object_name {
87 return quote! {
88 crate::alloc::UUID::<crate::prelude::TypeUUIDMarker>(#idx, std::marker::PhantomData)
89 }
90 .into();
91 }
92 }
93
94 quote_spanned!(
95 string_literal.span() =>
96 compile_error!("Unknown builtin type was not found in std/core.sus")
97 )
98 .into()
99}
100
101#[proc_macro]
102pub fn get_builtin_const(token_stream: TokenStream) -> TokenStream {
103 let string_literal: LitStr = parse_macro_input!(token_stream);
104
105 let object_name = string_literal.value();
106
107 let core_file_text = std::fs::read_to_string("std/core.sus").unwrap();
108
109 let re = Regex::new(r"__builtin__\s+const\s+.+\s+([a-zA-Z0-9_]+)\s*(?:#\(.*\))?\s*\{").unwrap();
110
111 for (idx, c) in re.captures_iter(&core_file_text).enumerate() {
112 let (_full, [found_name]) = c.extract();
113 if found_name == object_name {
114 return quote! {
115 crate::alloc::UUID::<crate::prelude::ConstantUUIDMarker>(#idx, std::marker::PhantomData)
116 }
117 .into();
118 }
119 }
120
121 quote_spanned!(
122 string_literal.span() =>
123 compile_error!("Unknown builtin const was not found in std/core.sus")
124 )
125 .into()
126}
127
128#[proc_macro]
131pub fn __debug_breakpoint(_input: TokenStream) -> TokenStream {
132 quote! {
133 if crate::debug::debugging_enabled() {
134 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
135 unsafe {
136 core::arch::asm!("int3");
137 }
138
139 #[cfg(all(target_arch = "x86_64", target_os = "windows"))]
140 unsafe {
141 core::arch::asm!("int3");
142 }
143
144 #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
145 unsafe {
146 core::arch::asm!("brk #0");
147 }
148
149 #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
150 unsafe {
151 core::arch::asm!("brk #0");
152 }
153 }
154 }
155 .into()
156}
157
158#[proc_macro]
161pub fn __debug_breakpoint_if(input: TokenStream) -> TokenStream {
162 let expr: syn::Expr = syn::parse_macro_input!(input as syn::Expr);
163 quote! {
164 if crate::debug::debugging_enabled() && (#expr) {
165 #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
166 unsafe {
167 core::arch::asm!("int3");
168 }
169
170 #[cfg(all(target_arch = "x86_64", target_os = "windows"))]
171 unsafe {
172 core::arch::asm!("int3");
173 }
174
175 #[cfg(all(target_arch = "aarch64", target_os = "linux"))]
176 unsafe {
177 core::arch::asm!("brk #0");
178 }
179
180 #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
181 unsafe {
182 core::arch::asm!("brk #0");
183 }
184 }
185 }
186 .into()
187}