Implements base functionality for __TYPE__ and __PROC__ (#366)

We basically just capture them early, and then treat them as unique
symbols. We don't replace inline or anything because the required
context isn't quite there.
This commit is contained in:
LemonInTheDark 2023-10-14 23:05:18 -07:00 committed by GitHub
parent 47ef0c58ab
commit d3dbed0fb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 0 deletions

View file

@ -544,6 +544,20 @@ impl<'o> WalkProc<'o> {
StaticType::None
}
},
Term::__TYPE__ => {
self.tab.use_symbol(self.ty.id, location);
StaticType::None
},
Term::__PROC__ => {
let Some(proc) = self.proc else {
return StaticType::None
};
if let Some(decl) = self.ty.get_proc_declaration(proc.name()) {
self.tab.use_symbol(decl.id, location);
}
StaticType::None
}
}
}

View file

@ -1738,6 +1738,8 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
let src = self.ty;
if let Some(proc) = self.ty.get_proc(unscoped_name) {
self.visit_call(location, src, proc, args, false, local_vars)
} else if unscoped_name == "__PROC__" {
self.visit_call(location, src, self.proc_ref, args, false, local_vars)
} else if unscoped_name == "SpacemanDMM_unlint" {
// Escape hatch for cases like `src` in macros used in
// global procs.
@ -1882,6 +1884,20 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
self.visit_arguments(location, args, local_vars);
Analysis::empty() // TODO
},
Term::__TYPE__ => {
let pop = dm::constants::Pop::from(self.ty.path.split('/').skip(1).map(ToOwned::to_owned).collect::<Vec<_>>().into_boxed_slice());
Analysis {
static_ty: StaticType::None,
aset: assumption_set![Assumption::IsPath(true, self.ty)],
value: Some(Constant::Prefab(Box::new(pop))),
fix_hint: None,
is_impure: None,
}
},
Term::__PROC__ => {
// Can't fuckin do it bros
Analysis::empty()
},
}
}

View file

@ -643,6 +643,10 @@ impl<'a, T: fmt::Display> fmt::Display for FormatTreePath<'a, T> {
/// A series of identifiers separated by path operators.
pub type TypePath = Vec<(PathOp, Ident)>;
pub fn make_typepath(segments: Vec<String>) -> TypePath {
segments.into_iter().fold(vec![], |mut acc, segment| { acc.push((PathOp::Slash, segment)); acc })
}
pub struct FormatTypePath<'a>(pub &'a [(PathOp, Ident)]);
impl<'a> fmt::Display for FormatTypePath<'a> {
@ -867,6 +871,10 @@ pub enum Term {
Resource(String),
/// An `as()` call, with an input type. Undocumented.
As(InputType),
/// A reference to our current proc's name
__PROC__,
/// A reference to the current proc/scope's type
__TYPE__,
// Non-function calls with recursive contents -----------------------------
/// An expression contained in a term.

View file

@ -783,6 +783,15 @@ impl<'a> ConstantFolder<'a> {
Term::Int(v) => Constant::Float(v as f32),
Term::Float(v) => Constant::from(v),
Term::Expr(expr) => self.expr(*expr, type_hint)?,
Term::__TYPE__ => {
if let Some(obj_tree) = &self.tree {
let typeval = TypeRef::new(obj_tree, self.ty).get();
let path = make_typepath(typeval.path.split("/").filter(|elem| *elem != "").map(|segment| segment.to_string()).collect());
Constant::Prefab(Box::new(self.prefab(Prefab::from(path))?))
} else {
return Err(self.error("No type context".to_owned()))
}
},
_ => return Err(self.error("non-constant expression".to_owned())),
})
}

View file

@ -2073,6 +2073,17 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> {
require!(self.exact(Token::Punct(Punctuation::RParen)));
Term::As(input_type)
},
// term :: __PROC__
Token::Ident(ref i, _) if i == "__PROC__" => {
// We cannot replace with the proc path yet, you don't need one it's fine
Term::__PROC__
},
// term :: __TYPE__
Token::Ident(ref i, _) if i == "__TYPE__" => {
// We cannot replace with the typepath yet, so we'll hand back a term we can parse later
Term::__TYPE__
},
// term :: ident arglist | ident
Token::Ident(i, _) => {