slovo/compiler/src/reserved.rs

164 lines
5.3 KiB
Rust

use crate::{
diag::Diagnostic,
sexpr::{Atom, SExpr, SExprKind},
token::Span,
};
const CURRENT_BETA_UNSUPPORTED: &str = "reserved but not supported in the current beta";
pub(crate) fn unsupported_reserved_type_diagnostic(file: &str, form: &SExpr) -> Option<Diagnostic> {
if let Some(name) = expect_ident(form) {
if is_generic_type_parameter_name(name) {
return Some(unsupported_generic_type_parameter(file, form.span, name));
}
}
let items = expect_list(form)?;
let head = items.first().and_then(expect_ident)?;
match head {
"map" => Some(
Diagnostic::new(
file,
"UnsupportedMapType",
format!("`map` types are {}", CURRENT_BETA_UNSUPPORTED),
)
.with_span(form.span)
.expected("supported concrete type")
.found(render_type_form(form))
.hint(
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
),
),
"set" => Some(
Diagnostic::new(
file,
"UnsupportedSetType",
format!("`set` types are {}", CURRENT_BETA_UNSUPPORTED),
)
.with_span(form.span)
.expected("supported concrete type")
.found(render_type_form(form))
.hint(
"use current concrete arrays, vectors, option/result, structs, enums, or scalars",
),
),
"vec" if items.len() != 2 => Some(
Diagnostic::new(
file,
"UnsupportedGenericTypeParameter",
format!("generic vector syntax is {}", CURRENT_BETA_UNSUPPORTED),
)
.with_span(form.span)
.expected("(vec i32), (vec i64), (vec f64), (vec bool), or (vec string)")
.found(render_type_form(form))
.hint("choose one current concrete vector family explicitly"),
),
_ => items
.iter()
.find_map(|item| unsupported_reserved_type_diagnostic(file, item)),
}
}
pub(crate) fn unsupported_generic_function(file: &str, span: Span) -> Diagnostic {
Diagnostic::new(
file,
"UnsupportedGenericFunction",
format!(
"generic function declarations are {}",
CURRENT_BETA_UNSUPPORTED
),
)
.with_span(span)
.expected("(fn name ((arg ConcreteType) ...) -> ConcreteType body...)")
.found("(type_params ...)")
.hint("write a concrete function for each currently supported type family")
}
pub(crate) fn unsupported_generic_type_alias(file: &str, span: Span) -> Diagnostic {
Diagnostic::new(
file,
"UnsupportedGenericTypeAlias",
format!(
"parameterized type aliases are {}",
CURRENT_BETA_UNSUPPORTED
),
)
.with_span(span)
.expected("(type Alias ConcreteType)")
.found("(type_params ...)")
.hint("aliases remain transparent names for concrete supported target types")
}
pub(crate) fn unsupported_generic_type_parameter(file: &str, span: Span, name: &str) -> Diagnostic {
Diagnostic::new(
file,
"UnsupportedGenericTypeParameter",
format!(
"generic type parameter `{}` is {}",
name, CURRENT_BETA_UNSUPPORTED
),
)
.with_span(span)
.expected("concrete supported type")
.found(name.to_string())
.hint("use a concrete promoted type such as `i32`, `string`, or `(vec i32)`")
}
pub(crate) fn unsupported_generic_standard_library_call(
file: &str,
span: Span,
name: &str,
) -> Diagnostic {
Diagnostic::new(
file,
"UnsupportedGenericStandardLibraryCall",
format!(
"generic standard-library call `{}` is {}",
name, CURRENT_BETA_UNSUPPORTED
),
)
.with_span(span)
.expected("promoted concrete standard-library function")
.found(name.to_string())
.hint("use current concrete families such as `std.vec.i32.empty`")
}
pub(crate) fn is_unsupported_generic_standard_library_call(name: &str) -> bool {
matches!(name, "std.vec.empty" | "std.result.map")
}
pub(crate) fn is_generic_type_parameter_name(name: &str) -> bool {
name.len() == 1 && name.bytes().all(|byte| byte.is_ascii_uppercase())
}
fn expect_list(expr: &SExpr) -> Option<&[SExpr]> {
match &expr.kind {
SExprKind::List(items) => Some(items),
_ => None,
}
}
fn expect_ident(expr: &SExpr) -> Option<&str> {
match &expr.kind {
SExprKind::Atom(Atom::Ident(name)) => Some(name),
_ => None,
}
}
fn render_type_form(form: &SExpr) -> String {
match &form.kind {
SExprKind::Atom(Atom::Ident(name)) => name.clone(),
SExprKind::Atom(Atom::Int(value)) => value.to_string(),
SExprKind::Atom(Atom::I64(value)) => format!("{}i64", value),
SExprKind::Atom(Atom::U32(value)) => format!("{}u32", value),
SExprKind::Atom(Atom::U64(value)) => format!("{}u64", value),
SExprKind::Atom(Atom::Float(value)) => value.to_string(),
SExprKind::Atom(Atom::String(value)) => format!("{:?}", value),
SExprKind::Atom(Atom::Arrow) => "->".to_string(),
SExprKind::List(items) => {
let parts = items.iter().map(render_type_form).collect::<Vec<_>>();
format!("({})", parts.join(" "))
}
}
}