164 lines
5.3 KiB
Rust
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(" "))
|
|
}
|
|
}
|
|
}
|