From 56ade074b9c93d75f1845a70a07362aa66de2b10 Mon Sep 17 00:00:00 2001 From: James Gibson Date: Mon, 29 Jan 2024 15:20:30 +0000 Subject: [PATCH] Fixed define field completions --- src/ast/statement/define/field.rs | 4 +- src/features/completions/statements/define.rs | 21 ++++--- src/features/diagnostics/statement/define.rs | 18 ++++-- src/ls/backend.rs | 6 +- src/ls/properties.rs | 5 +- src/parser/statement/define/field.rs | 63 ++++++++----------- test.surql | 57 +++++++---------- 7 files changed, 82 insertions(+), 92 deletions(-) diff --git a/src/ast/statement/define/field.rs b/src/ast/statement/define/field.rs index 3c67971..3b626ac 100644 --- a/src/ast/statement/define/field.rs +++ b/src/ast/statement/define/field.rs @@ -6,7 +6,7 @@ use super::table::Permission; pub struct DefineField { pub name: Spanned, pub parents: Vec>, - pub table_name: Spanned, - pub type_: Spanned, + pub table_name: Option>, + pub type_: Option>, pub permission: Option>, } diff --git a/src/features/completions/statements/define.rs b/src/features/completions/statements/define.rs index d4996ff..8c01ac4 100644 --- a/src/features/completions/statements/define.rs +++ b/src/features/completions/statements/define.rs @@ -22,14 +22,19 @@ impl HasCompletionItems for DefineStatement { vec![] } DefineStatement::Field(field) => { - let table_name_range = span_to_range(&field.0.table_name.1, rope).unwrap(); - if table_name_range.start <= position && position <= table_name_range.end { - return get_completion_items_for_table_name(scope); - } - let type_range = span_to_range(&field.0.type_.1, rope).unwrap(); - if type_range.start <= position && position <= type_range.end { - return field.0.type_.0.get_completion_items(scope, position, rope); - } + if let Some(table_name) = &field.0.table_name { + let table_name_range = span_to_range(&table_name.1, rope).unwrap(); + if table_name_range.start <= position && position <= table_name_range.end { + return get_completion_items_for_table_name(scope); + } + + if let Some(type_) = &field.0.type_ { + let type_range = span_to_range(&type_.1, rope).unwrap(); + if type_range.start <= position && position <= type_range.end { + return type_.0.get_completion_items(scope, position, rope); + } + } + }; vec![] } } diff --git a/src/features/diagnostics/statement/define.rs b/src/features/diagnostics/statement/define.rs index e172eb0..88ed20f 100644 --- a/src/features/diagnostics/statement/define.rs +++ b/src/features/diagnostics/statement/define.rs @@ -3,7 +3,7 @@ use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity}; use crate::{ ast::statement::define::DefineStatement, - declarations::{field::Field, scoped_item::ScopedItems, type_::Type}, + declarations::{scoped_item::ScopedItems, type_::Type}, features::diagnostics::diagnostic::HasDiagnostic, ls::properties::parse_declared_type, util::{range::span_to_range, span::Spanned}, @@ -22,9 +22,12 @@ impl HasDiagnostic for Spanned<&DefineStatement> { }], }, DefineStatement::Field(field) => { - let table_name = &field.0.table_name.0; + if field.0.table_name.is_none() { + return vec![]; + } + let table_name = &field.0.table_name.clone().unwrap(); let field_name = &field.0.name.0; - match scope.table_definitions.get(table_name) { + match scope.table_definitions.get(&table_name.0) { Some(table) => { let mut scoped_type = table.clone(); for parent in &field.0.parents { @@ -48,9 +51,14 @@ impl HasDiagnostic for Spanned<&DefineStatement> { }]; } } + if field.0.type_.is_none() { + return vec![]; + } + let field_type = field.0.type_.clone().unwrap(); + match scoped_type.get_field(field_name) { Some(ty) => { - let declared_type = parse_declared_type(&field.0.type_.0); + let declared_type = parse_declared_type(&field_type.0); let both_object = match (&ty.ty, &declared_type) { (Type::Object(_), Type::Object(_)) => true, _ => false, @@ -79,7 +87,7 @@ impl HasDiagnostic for Spanned<&DefineStatement> { vec![] } None => vec![Diagnostic { - range: span_to_range(&field.0.table_name.1, rope).unwrap(), + range: span_to_range(&table_name.1, rope).unwrap(), severity: Some(DiagnosticSeverity::ERROR), message: "Table not found".to_string(), ..Default::default() diff --git a/src/ls/backend.rs b/src/ls/backend.rs index 71d4e22..85daeeb 100644 --- a/src/ls/backend.rs +++ b/src/ls/backend.rs @@ -80,11 +80,7 @@ impl LanguageServer for Backend { match parse_config(self).await { Ok(_) => { let defs = get_table_defs(&self).await; - let scope = ScopedItems { - table_definitions: defs, - ..Default::default() - }; - self.state.lock().await.table_definitions = scope.table_definitions; + self.state.lock().await.table_definitions = defs; } Err(err) => { self.client diff --git a/src/ls/properties.rs b/src/ls/properties.rs index 849c737..71d6255 100644 --- a/src/ls/properties.rs +++ b/src/ls/properties.rs @@ -211,7 +211,8 @@ pub async fn parse_table_defs( .collect::>() .join("."); if parent == parents { - if &field.type_.0.name.0 == "object" { + let field_type = &field.type_.clone().unwrap(); + if &field_type.0.name.0 == "object" { let new_parent = if parents == "" { field.name.0.clone() } else { @@ -225,7 +226,7 @@ pub async fn parse_table_defs( is_required: false, }); } else { - let ty = parse_declared_type(&field.type_.0); + let ty = parse_declared_type(&field_type.0); fields.push(Field { name: field.name.0.clone(), is_required: match ty { diff --git a/src/parser/statement/define/field.rs b/src/parser/statement/define/field.rs index fddedde..92663ee 100644 --- a/src/parser/statement/define/field.rs +++ b/src/parser/statement/define/field.rs @@ -1,7 +1,7 @@ use chumsky::{primitive::just, recovery::via_parser, select, IterParser, Parser}; use crate::{ - ast::{parser::Extra, statement::define::field::DefineField, type_::Type}, + ast::{parser::Extra, statement::define::field::DefineField}, lexer::{keyword::Keyword, token::Token}, parser::{expr::newline::optional_new_line, type_::type_parser}, util::span::ParserInput, @@ -24,42 +24,33 @@ pub fn define_field_parser<'tokens, 'src: 'tokens>( .collect::>(); let type_ = just(Token::Keyword(Keyword::Type)) - .ignore_then(optional_new_line().ignore_then(type_parser())) - .recover_with(via_parser(just(Token::Keyword(Keyword::Type)).map_with( - |_, s| { - ( - Type { - name: ("".to_string(), s.span()), - args: vec![], - }, - s.span(), - ) - }, - ))); + .ignore_then(optional_new_line().ignore_then(type_parser()).map(|x| Some(x))) + .recover_with(via_parser(just(Token::Keyword(Keyword::Type)).map(|_| None))); - just(Token::Keyword(Keyword::Field)) + + let on = just(Token::Keyword(Keyword::On)) + .then(just(Token::Keyword(Keyword::Table)).or_not()); + + let table = on + .clone() + .ignore_then(ident.map(|x| Some(x))) + .recover_with(via_parser(on.map(|_| None))); + + let field = just(Token::Keyword(Keyword::Field)) .ignore_then(parents) .then(ident.clone()) - .then_ignore(optional_new_line().then(just(Token::Keyword(Keyword::On)))) - .then_ignore( - optional_new_line() - .then(just(Token::Keyword(Keyword::Table))) - .or_not(), - ) - .then(ident) - .then(optional_new_line().ignore_then(type_)) - .then( - optional_new_line() - .ignore_then(permission_parser()) - .or_not(), - ) - .map( - |((((parents, name), table_name), type_), permission)| DefineField { - name, - parents, - table_name, - type_, - permission, - }, - ) + .then(table); + + field.clone().then(type_).then(permission_parser().or_not()) + .map(|((((parents, name), table_name), type_), permission)| { + DefineField { + name, parents, table_name, type_, permission + } + }) + .recover_with(via_parser(field.map(|((parents, name), table_name)| { + DefineField { + name, parents, table_name, type_: None, permission: None + } + }))) + } diff --git a/test.surql b/test.surql index a25cdb4..a6b3beb 100644 --- a/test.surql +++ b/test.surql @@ -1,40 +1,29 @@ -define table todo; -define field title on todo type string; -define field description on todo type string; -define field tasks on todo type array; +define table test; +define field some on test type option; -let $created = (create todo content { - title: "test", - description: "test", - tasks: ["test1", "test2"], - }); -return $created.title; - -let $nested_array_of_obj = [ - [ - { test: "data1"}, - { test: "data2"} - ], - [ - { test: "data3"}, - { test: "data4"} - ] -]; - -let $test_thing = $nested_array_of_obj.test; - -define table item; -define field name on item type string; +define table rel; +define field in on rel type record +define field out on rel type record -define table person; -define field name on person type any; -define table purchase; -define field in on purchase type record; -define field out on purchase type record; +return { + let $first = (create test content { + some: "First thing" + }); -let $person = (create person content { name: "test" }); + let $second = (create test content { + some: "Second thing" + }); -let $some = (select title, "Hello" as my_string from todo); + create rel content { + in: $first[0].id, + out: $second[0].id, + }; +}; -return $some[0].title; +return { + let $first = (create test content { + some: "First thing" + }); + return $first.id[0]; +};