From 74ff938d0eecdfe0912ad327c397c66b0181bd18 Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 1 Oct 2023 19:24:55 -0700 Subject: [PATCH 1/2] Implements base functionality for __TYPE__ and __PROC__ 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. --- crates/dm-langserver/src/find_references.rs | 14 ++++++++++++++ crates/dreamchecker/src/lib.rs | 16 ++++++++++++++++ crates/dreammaker/src/ast.rs | 8 ++++++++ crates/dreammaker/src/constants.rs | 9 +++++++++ crates/dreammaker/src/parser.rs | 11 +++++++++++ 5 files changed, 58 insertions(+) diff --git a/crates/dm-langserver/src/find_references.rs b/crates/dm-langserver/src/find_references.rs index 21e6156c..19727c56 100644 --- a/crates/dm-langserver/src/find_references.rs +++ b/crates/dm-langserver/src/find_references.rs @@ -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 + } } } diff --git a/crates/dreamchecker/src/lib.rs b/crates/dreamchecker/src/lib.rs index d834efd8..6fcb5b19 100644 --- a/crates/dreamchecker/src/lib.rs +++ b/crates/dreamchecker/src/lib.rs @@ -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::>().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() + }, } } diff --git a/crates/dreammaker/src/ast.rs b/crates/dreammaker/src/ast.rs index 49d8086a..2c7a8684 100644 --- a/crates/dreammaker/src/ast.rs +++ b/crates/dreammaker/src/ast.rs @@ -628,6 +628,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) -> 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> { @@ -852,6 +856,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. diff --git a/crates/dreammaker/src/constants.rs b/crates/dreammaker/src/constants.rs index 40adc04d..e0e1bf4a 100644 --- a/crates/dreammaker/src/constants.rs +++ b/crates/dreammaker/src/constants.rs @@ -769,6 +769,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())), }) } diff --git a/crates/dreammaker/src/parser.rs b/crates/dreammaker/src/parser.rs index cde62424..72f30554 100644 --- a/crates/dreammaker/src/parser.rs +++ b/crates/dreammaker/src/parser.rs @@ -2065,7 +2065,18 @@ 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, _) => { let first_token = self.updated_location(); From d787096e9b1c46b251605b9204bd7b9982645499 Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Sat, 14 Oct 2023 23:05:22 -0700 Subject: [PATCH 2/2] Fix indentation --- crates/dreammaker/src/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/dreammaker/src/parser.rs b/crates/dreammaker/src/parser.rs index 72f30554..cd5a2d90 100644 --- a/crates/dreammaker/src/parser.rs +++ b/crates/dreammaker/src/parser.rs @@ -2069,14 +2069,14 @@ impl<'ctx, 'an, 'inp> Parser<'ctx, 'an, 'inp> { 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, _) => { let first_token = self.updated_location();