chore(els): improve signature help

This commit is contained in:
Shunsuke Shibayama 2023-02-27 03:20:44 +09:00
parent e6b7e65d93
commit 1aa83f140a
26 changed files with 475 additions and 334 deletions

View file

@ -11,7 +11,7 @@ use erg_compiler::hir::Expr;
use lsp_types::{CodeAction, CodeActionKind, CodeActionParams, TextEdit, Url, WorkspaceEdit};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
@ -25,11 +25,11 @@ impl<Checker: BuildRunnable> Server<Checker> {
let diag = diags.remove(0);
let mut map = HashMap::new();
let Some(visitor) = self.get_visitor(&uri) else {
Self::send_log("visitor not found")?;
send_log("visitor not found")?;
return Ok(None);
};
let Some(artifact) = self.artifacts.get(&uri) else {
Self::send_log("artifact not found")?;
send_log("artifact not found")?;
return Ok(None);
};
let warns = artifact
@ -45,7 +45,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
match visitor.get_min_expr(&token) {
Some(Expr::Def(def)) => {
let Some(mut range) = util::loc_to_range(def.loc()) else {
Self::send_log("range not found")?;
send_log("range not found")?;
continue;
};
let next = lsp_types::Range {
@ -67,7 +67,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
Some(";") => range.end.character += 1,
Some(other) => {
Self::send_log(format!("? {other}"))?;
send_log(format!("? {other}"))?;
}
}
let edit = TextEdit::new(range, "".to_string());
@ -161,7 +161,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
pub(crate) fn send_code_action(&self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("code action requested: {msg}"))?;
send_log(format!("code action requested: {msg}"))?;
let params = CodeActionParams::deserialize(&msg["params"])?;
let result = match params
.context
@ -172,12 +172,10 @@ impl<Checker: BuildRunnable> Server<Checker> {
Some("quickfix") => self.send_quick_fix(msg, params)?,
None => self.send_normal_action(msg, params)?,
Some(other) => {
Self::send_log(&format!("Unknown code action requested: {other}"))?;
send_log(&format!("Unknown code action requested: {other}"))?;
vec![]
}
};
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
}

View file

@ -7,12 +7,12 @@ use erg_compiler::hir::Expr;
use lsp_types::{CodeLens, CodeLensParams, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn show_code_lens(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log("code lens requested")?;
send_log("code lens requested")?;
let params = CodeLensParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document.uri);
// TODO: parallelize
@ -21,9 +21,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
self.send_class_inherits_lens(&uri)?,
]
.concat();
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
fn send_trait_impls_lens(&mut self, uri: &Url) -> ELSResult<Vec<CodeLens>> {

View file

@ -9,18 +9,18 @@ use erg_compiler::hir::Expr;
use lsp_types::{ExecuteCommandParams, Location, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn execute_command(&mut self, msg: &Value) -> ELSResult<()> {
let params = ExecuteCommandParams::deserialize(&msg["params"])?;
Self::send_log(format!("command requested: {}", params.command))?;
send_log(format!("command requested: {}", params.command))?;
#[allow(clippy::match_single_binding)]
match &params.command[..] {
other => {
Self::send_log(format!("unknown command: {other}"))?;
Self::send(
send_log(format!("unknown command: {other}"))?;
send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": Value::Null }),
)
}

View file

@ -17,7 +17,7 @@ use lsp_types::{
MarkupContent, MarkupKind,
};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
fn mark_to_string(mark: MarkedString) -> String {
@ -70,7 +70,7 @@ impl CompletionOrder {
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn show_completion(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("completion requested: {msg}"))?;
send_log(format!("completion requested: {msg}"))?;
let params = CompletionParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document_position.text_document.uri);
let path = util::uri_to_path(&uri);
@ -84,7 +84,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
Some(":") => AccessKind::Attr, // or type ascription
_ => AccessKind::Name,
};
Self::send_log(format!("AccessKind: {acc_kind:?}"))?;
send_log(format!("AccessKind: {acc_kind:?}"))?;
let mut result: Vec<CompletionItem> = vec![];
let contexts = if acc_kind.is_local() {
let prev_token = self.file_cache.get_token_relatively(&uri, pos, -1)?;
@ -101,7 +101,6 @@ impl<Checker: BuildRunnable> Server<Checker> {
} else {
self.get_receiver_ctxs(&uri, pos)?
};
// Self::send_log(format!("contexts: {:?}", contexts.iter().map(|ctx| &ctx.name).collect::<Vec<_>>())).unwrap();
for (name, vi) in contexts.into_iter().flat_map(|ctx| ctx.dir()) {
if acc_kind.is_attr() && vi.vis.is_private() {
continue;
@ -147,19 +146,17 @@ impl<Checker: BuildRunnable> Server<Checker> {
item.data = Some(Value::String(vi.def_loc.to_string()));
result.push(item);
}
Self::send_log(format!("completion items: {}", result.len()))?;
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send_log(format!("completion items: {}", result.len()))?;
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
pub(crate) fn resolve_completion(&self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("completion resolve requested: {msg}"))?;
send_log(format!("completion resolve requested: {msg}"))?;
let mut item = CompletionItem::deserialize(&msg["params"])?;
if let Some(data) = &item.data {
let mut contents = vec![];
let Ok(def_loc) = data.as_str().unwrap().parse::<AbsLocation>() else {
return Self::send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": item }));
return send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": item }));
};
self.show_doc_comment(None, &mut contents, &def_loc)?;
let mut contents = contents.into_iter().map(mark_to_string).collect::<Vec<_>>();
@ -169,6 +166,6 @@ impl<Checker: BuildRunnable> Server<Checker> {
value: contents.join("\n"),
}));
}
Self::send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": item }))
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": item }))
}
}

View file

@ -8,7 +8,7 @@ use erg_compiler::varinfo::VarInfo;
use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
@ -18,18 +18,18 @@ impl<Checker: BuildRunnable> Server<Checker> {
token: &Token,
) -> ELSResult<Option<VarInfo>> {
if !token.category_is(TokenCategory::Symbol) {
Self::send_log(format!("not symbol: {token}"))?;
send_log(format!("not symbol: {token}"))?;
Ok(None)
} else if let Some(visitor) = self.get_visitor(uri) {
Ok(visitor.get_info(token))
} else {
Self::send_log("not found")?;
send_log("not found")?;
Ok(None)
}
}
pub(crate) fn show_definition(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("definition requested: {msg}"))?;
send_log(format!("definition requested: {msg}"))?;
let params = GotoDefinitionParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document_position_params.text_document.uri);
let pos = params.text_document_position_params.position;
@ -38,13 +38,13 @@ impl<Checker: BuildRunnable> Server<Checker> {
match (vi.def_loc.module, util::loc_to_range(vi.def_loc.loc)) {
(Some(path), Some(range)) => {
let def_uri = util::normalize_url(Url::from_file_path(path).unwrap());
Self::send_log("found")?;
send_log("found")?;
GotoDefinitionResponse::Array(vec![lsp_types::Location::new(
def_uri, range,
)])
}
_ => {
Self::send_log("not found (maybe builtin)")?;
send_log("not found (maybe builtin)")?;
GotoDefinitionResponse::Array(vec![])
}
}
@ -52,11 +52,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
GotoDefinitionResponse::Array(vec![])
}
} else {
Self::send_log("lex error occurred")?;
send_log("lex error occurred")?;
GotoDefinitionResponse::Array(vec![])
};
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
}

View file

@ -8,12 +8,12 @@ use erg_compiler::error::CompileErrors;
use lsp_types::{Diagnostic, DiagnosticSeverity, Position, PublishDiagnosticsParams, Range, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn check_file<S: Into<String>>(&mut self, uri: Url, code: S) -> ELSResult<()> {
Self::send_log(format!("checking {uri}"))?;
send_log(format!("checking {uri}"))?;
let path = util::uri_to_path(&uri);
let mode = if path.to_string_lossy().ends_with(".d.er") {
"declare"
@ -27,19 +27,19 @@ impl<Checker: BuildRunnable> Server<Checker> {
};
match checker.build(code.into(), mode) {
Ok(artifact) => {
Self::send_log(format!("checking {uri} passed"))?;
send_log(format!("checking {uri} passed"))?;
let uri_and_diags = self.make_uri_and_diags(uri.clone(), artifact.warns.clone());
// clear previous diagnostics
self.send_diagnostics(uri.clone(), vec![])?;
for (uri, diags) in uri_and_diags.into_iter() {
Self::send_log(format!("{uri}, warns: {}", diags.len()))?;
send_log(format!("{uri}, warns: {}", diags.len()))?;
self.send_diagnostics(uri, diags)?;
}
self.artifacts.insert(uri.clone(), artifact.into());
}
Err(artifact) => {
Self::send_log(format!("found errors: {}", artifact.errors.len()))?;
Self::send_log(format!("found warns: {}", artifact.warns.len()))?;
send_log(format!("found errors: {}", artifact.errors.len()))?;
send_log(format!("found warns: {}", artifact.warns.len()))?;
let diags = artifact
.errors
.clone()
@ -51,14 +51,14 @@ impl<Checker: BuildRunnable> Server<Checker> {
self.send_diagnostics(uri.clone(), vec![])?;
}
for (uri, diags) in uri_and_diags.into_iter() {
Self::send_log(format!("{uri}, errs & warns: {}", diags.len()))?;
send_log(format!("{uri}, errs & warns: {}", diags.len()))?;
self.send_diagnostics(uri, diags)?;
}
self.artifacts.insert(uri.clone(), artifact);
}
}
if let Some(module) = checker.pop_context() {
Self::send_log(format!("{uri}: {}", module.context.name))?;
send_log(format!("{uri}: {}", module.context.name))?;
self.modules.insert(uri.clone(), module);
}
let dependents = self.dependents_of(&uri);
@ -132,13 +132,13 @@ impl<Checker: BuildRunnable> Server<Checker> {
.map(|doc| doc.publish_diagnostics.is_some())
.unwrap_or(false)
{
Self::send(&json!({
send(&json!({
"jsonrpc": "2.0",
"method": "textDocument/publishDiagnostics",
"params": params,
}))?;
} else {
Self::send_log("the client does not support diagnostics")?;
send_log("the client does not support diagnostics")?;
}
Ok(())
}

View file

@ -9,7 +9,7 @@ use erg_compiler::varinfo::AbsLocation;
use lsp_types::{HoverContents, HoverParams, MarkedString, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
const PROG_LANG: &str = if cfg!(feature = "py_compatible") {
@ -99,7 +99,7 @@ macro_rules! next {
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn show_hover(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("hover requested : {msg}"))?;
send_log(format!("hover requested : {msg}"))?;
let params = HoverParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document_position_params.text_document.uri);
let pos = params.text_document_position_params.position;
@ -184,12 +184,10 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
}
} else {
Self::send_log("lex error")?;
send_log("lex error")?;
}
let result = json!({ "contents": HoverContents::Array(sort_hovers(contents)) });
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
pub(crate) fn show_doc_comment(

View file

@ -15,7 +15,7 @@ use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact};
use erg_compiler::hir::{Block, Call, ClassDef, Def, Expr, Lambda, Params, PatchDef, Signature};
use lsp_types::{InlayHint, InlayHintKind, InlayHintLabel, InlayHintParams};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
use crate::util::loc_to_range;
@ -90,7 +90,7 @@ fn param_anot<D: std::fmt::Display>(ln_begin: u32, col_begin: u32, name: D) -> I
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn get_inlay_hint(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("inlay hint request: {msg}"))?;
send_log(format!("inlay hint request: {msg}"))?;
let params = InlayHintParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document.uri);
let mut result = vec![];
@ -102,9 +102,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
result.extend(self.get_expr_hint(chunk));
}
}
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
fn get_expr_hint(&self, expr: &Expr) -> Vec<InlayHint> {

View file

@ -7,7 +7,7 @@ use erg_compiler::varinfo::AbsLocation;
use lsp_types::{Position, ReferenceParams, Url};
use crate::server::{ELSResult, Server};
use crate::server::{send, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
@ -16,14 +16,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
let uri = util::normalize_url(params.text_document_position.text_document.uri);
let pos = params.text_document_position.position;
let result = self.show_refs_inner(&uri, pos);
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
fn show_refs_inner(&self, uri: &Url, pos: Position) -> Vec<lsp_types::Location> {
if let Some(tok) = self.file_cache.get_token(uri, pos) {
// Self::send_log(format!("token: {tok}"))?;
// send_log(format!("token: {tok}"))?;
if let Some(visitor) = self.get_visitor(uri) {
if let Some(vi) = visitor.get_info(&tok) {
return self.get_refs_from_abs_loc(&vi.def_loc);
@ -36,7 +34,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn get_refs_from_abs_loc(&self, referee: &AbsLocation) -> Vec<lsp_types::Location> {
let mut refs = vec![];
if let Some(value) = self.get_index().get_refs(referee) {
// Self::send_log(format!("referrers: {referrers:?}"))?;
// send_log(format!("referrers: {referrers:?}"))?;
for referrer in value.referrers.iter() {
if let (Some(path), Some(range)) =
(&referrer.module, util::loc_to_range(referrer.loc))

View file

@ -20,17 +20,17 @@ use lsp_types::{
RenameFilesParams, RenameParams, ResourceOp, TextDocumentEdit, TextEdit, Url, WorkspaceEdit,
};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_error_info, send_log, ELSResult, Server};
use crate::util;
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn rename(&mut self, msg: &Value) -> ELSResult<()> {
let params = RenameParams::deserialize(&msg["params"])?;
Self::send_log(format!("rename request: {params:?}"))?;
send_log(format!("rename request: {params:?}"))?;
let uri = util::normalize_url(params.text_document_position.text_document.uri);
let pos = params.text_document_position.position;
if let Some(tok) = self.file_cache.get_token(&uri, pos) {
// Self::send_log(format!("token: {tok}"))?;
// send_log(format!("token: {tok}"))?;
if let Some(visitor) = self.get_visitor(&uri) {
if let Some(vi) = visitor.get_info(&tok) {
let mut changes: HashMap<Url, Vec<TextEdit>> = HashMap::new();
@ -61,14 +61,14 @@ impl<Checker: BuildRunnable> Server<Checker> {
_ => format!("this {kind} cannot be renamed"),
};
let edit = WorkspaceEdit::new(changes);
Self::send(
send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": edit }),
)?;
return Self::send_error_info(error_reason);
return send_error_info(error_reason);
}
Self::commit_change(&mut changes, &vi.def_loc, params.new_name.clone());
if let Some(value) = self.get_index().get_refs(&vi.def_loc) {
// Self::send_log(format!("referrers: {referrers:?}"))?;
// send_log(format!("referrers: {referrers:?}"))?;
for referrer in value.referrers.iter() {
Self::commit_change(&mut changes, referrer, params.new_name.clone());
}
@ -79,11 +79,11 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
let timestamps = self.get_timestamps(changes.keys());
let edit = WorkspaceEdit::new(changes);
Self::send(
send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": edit }),
)?;
for _ in 0..20 {
Self::send_log("waiting for file to be modified...")?;
send_log("waiting for file to be modified...")?;
if self.all_changed(&timestamps) {
break;
}
@ -99,9 +99,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
}
}
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": Value::Null }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": Value::Null }))
}
fn commit_change(
@ -269,7 +267,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
pub(crate) fn rename_files(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log("workspace/willRenameFiles request")?;
send_log("workspace/willRenameFiles request")?;
let params = RenameFilesParams::deserialize(msg["params"].clone())?;
let mut edits = HashMap::new();
let mut renames = vec![];
@ -307,6 +305,6 @@ impl<Checker: BuildRunnable> Server<Checker> {
document_changes: Some(changes),
..Default::default()
};
Self::send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": edit }))
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": edit }))
}
}

View file

@ -17,7 +17,7 @@ use erg_compiler::ASTBuilder;
use lsp_types::{SemanticTokenType, SemanticTokens, SemanticTokensParams};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
#[derive(Debug)]
@ -284,7 +284,7 @@ impl ASTSemanticState {
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn get_semantic_tokens_full(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("full semantic tokens request: {msg}"))?;
send_log(format!("full semantic tokens request: {msg}"))?;
let params = SemanticTokensParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document.uri);
let path = util::uri_to_path(&uri);
@ -298,8 +298,6 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
Err(_) => json!(null),
};
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
}

View file

@ -16,6 +16,7 @@ use erg_common::normalize_path;
use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact};
use erg_compiler::build_hir::HIRBuilder;
use erg_compiler::context::{Context, ModuleContext};
use erg_compiler::hir::Expr;
use erg_compiler::module::{SharedCompilerResource, SharedModuleIndex};
use erg_compiler::ty::HasType;
@ -71,7 +72,7 @@ impl From<&str> for ELSFeatures {
macro_rules! _log {
($($arg:tt)*) => {
Self::send_log(format!($($arg)*)).unwrap();
send_log(format!($($arg)*)).unwrap();
};
}
@ -110,6 +111,34 @@ fn read_exact(len: usize) -> io::Result<Vec<u8>> {
})
}
pub(crate) fn send<T: ?Sized + Serialize>(message: &T) -> ELSResult<()> {
send_stdout(message)
}
pub(crate) fn send_log<S: Into<String>>(msg: S) -> ELSResult<()> {
send(&LogMessage::new(msg))
}
#[allow(unused)]
pub(crate) fn send_info<S: Into<String>>(msg: S) -> ELSResult<()> {
send(&ShowMessage::info(msg))
}
pub(crate) fn send_error_info<S: Into<String>>(msg: S) -> ELSResult<()> {
send(&ShowMessage::error(msg))
}
pub(crate) fn send_error<S: Into<String>>(id: Option<i64>, code: i64, msg: S) -> ELSResult<()> {
send(&ErrorMessage::new(
id,
json!({ "code": code, "message": msg.into() }),
))
}
pub(crate) fn send_invalid_req_error() -> ELSResult<()> {
send_error(None, -32601, "received an invalid request")
}
/// A Language Server, which can be used any object implementing `BuildRunnable` internally by passing it as a generic parameter.
#[derive(Debug)]
pub struct Server<Checker: BuildRunnable = HIRBuilder> {
@ -120,7 +149,8 @@ pub struct Server<Checker: BuildRunnable = HIRBuilder> {
pub(crate) file_cache: FileCache,
pub(crate) modules: Dict<Url, ModuleContext>,
pub(crate) artifacts: Dict<Url, IncompleteArtifact>,
_checker: std::marker::PhantomData<Checker>,
pub(crate) current_sig: Option<Expr>,
pub(crate) _checker: std::marker::PhantomData<Checker>,
}
impl<Checker: BuildRunnable> Server<Checker> {
@ -133,6 +163,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
file_cache: FileCache::new(),
modules: Dict::new(),
artifacts: Dict::new(),
current_sig: None,
_checker: std::marker::PhantomData,
}
}
@ -155,11 +186,11 @@ impl<Checker: BuildRunnable> Server<Checker> {
#[allow(clippy::field_reassign_with_default)]
fn init(&mut self, msg: &Value, id: i64) -> ELSResult<()> {
Self::send_log("initializing ELS")?;
send_log("initializing ELS")?;
// #[allow(clippy::collapsible_if)]
if msg.get("params").is_some() && msg["params"].get("capabilities").is_some() {
self.client_capas = ClientCapabilities::deserialize(&msg["params"]["capabilities"])?;
// Self::send_log(format!("set client capabilities: {:?}", self.client_capas))?;
// send_log(format!("set client capabilities: {:?}", self.client_capas))?;
}
let mut args = self.cfg.runtime_args.iter();
let mut disabled_features = vec![];
@ -247,7 +278,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
result.capabilities.code_lens_provider = Some(CodeLensOptions {
resolve_provider: Some(false),
});
Self::send(&json!({
send(&json!({
"jsonrpc": "2.0",
"id": id,
"result": result,
@ -255,13 +286,13 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
fn exit(&self) -> ELSResult<()> {
Self::send_log("exiting ELS")?;
send_log("exiting ELS")?;
std::process::exit(0);
}
fn shutdown(&self, id: i64) -> ELSResult<()> {
Self::send_log("shutting down ELS")?;
Self::send(&json!({
send_log("shutting down ELS")?;
send(&json!({
"jsonrpc": "2.0",
"id": id,
"result": json!(null),
@ -346,7 +377,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
Ok(())
}
(None, Some(notification)) => self.handle_notification(&msg, notification),
_ => Self::send_invalid_req_error(),
_ => send_invalid_req_error(),
}
}
@ -367,19 +398,19 @@ impl<Checker: BuildRunnable> Server<Checker> {
"textDocument/codeLens" => self.show_code_lens(msg),
"workspace/willRenameFiles" => self.rename_files(msg),
"workspace/executeCommand" => self.execute_command(msg),
other => Self::send_error(Some(id), -32600, format!("{other} is not supported")),
other => send_error(Some(id), -32600, format!("{other} is not supported")),
}
}
fn handle_notification(&mut self, msg: &Value, method: &str) -> ELSResult<()> {
match method {
"initialized" => Self::send_log("successfully bound"),
"initialized" => send_log("successfully bound"),
"exit" => self.exit(),
"textDocument/didOpen" => {
let uri = util::parse_and_normalize_url(
msg["params"]["textDocument"]["uri"].as_str().unwrap(),
)?;
Self::send_log(format!("{method}: {uri}"))?;
send_log(format!("{method}: {uri}"))?;
let code = msg["params"]["textDocument"]["text"].as_str().unwrap();
self.file_cache.update(&uri, code.to_string());
self.check_file(uri, code)
@ -388,49 +419,21 @@ impl<Checker: BuildRunnable> Server<Checker> {
let uri = util::parse_and_normalize_url(
msg["params"]["textDocument"]["uri"].as_str().unwrap(),
)?;
Self::send_log(format!("{method}: {uri}"))?;
send_log(format!("{method}: {uri}"))?;
let code = util::get_code_from_uri(&uri)?;
self.clear_cache(&uri);
self.check_file(uri, &code)
}
"textDocument/didChange" => {
let params = DidChangeTextDocumentParams::deserialize(msg["params"].clone())?;
// Self::send_log(format!("{method}: {params:?}"))?;
self.file_cache.incremental_update(params);
send_log("file cache updated")?;
Ok(())
}
_ => Self::send_log(format!("received notification: {method}")),
_ => send_log(format!("received notification: {method}")),
}
}
pub(crate) fn send<T: ?Sized + Serialize>(message: &T) -> ELSResult<()> {
send_stdout(message)
}
pub(crate) fn send_log<S: Into<String>>(msg: S) -> ELSResult<()> {
Self::send(&LogMessage::new(msg))
}
#[allow(unused)]
pub(crate) fn send_info<S: Into<String>>(msg: S) -> ELSResult<()> {
Self::send(&ShowMessage::info(msg))
}
pub(crate) fn send_error_info<S: Into<String>>(msg: S) -> ELSResult<()> {
Self::send(&ShowMessage::error(msg))
}
pub(crate) fn send_error<S: Into<String>>(id: Option<i64>, code: i64, msg: S) -> ELSResult<()> {
Self::send(&ErrorMessage::new(
id,
json!({ "code": code, "message": msg.into() }),
))
}
pub(crate) fn send_invalid_req_error() -> ELSResult<()> {
Self::send_error(None, -32601, "received an invalid request")
}
pub(crate) fn get_visitor(&self, uri: &Url) -> Option<HIRVisitor> {
self.artifacts
.get(uri)?
@ -440,7 +443,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
}
pub(crate) fn get_local_ctx(&self, uri: &Url, pos: Position) -> Vec<&Context> {
// Self::send_log(format!("scope: {:?}\n", self.module.as_ref().unwrap().scope.keys())).unwrap();
// send_log(format!("scope: {:?}\n", self.module.as_ref().unwrap().scope.keys())).unwrap();
let mut ctxs = vec![];
if let Some(visitor) = self.get_visitor(uri) {
let ns = visitor.get_namespace(pos);
@ -467,7 +470,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
.file_cache
.get_token_relatively(uri, attr_marker_pos, -2)?;
if let Some(token) = maybe_token {
Self::send_log(format!("token: {token}"))?;
// send_log(format!("token: {token}"))?;
let mut ctxs = vec![];
if let Some(visitor) = self.get_visitor(uri) {
if let Some(expr) = visitor.get_min_expr(&token) {
@ -482,11 +485,13 @@ impl<Checker: BuildRunnable> Server<Checker> {
{
ctxs.push(singular_ctx);
}
} else {
send_log("expr not found: {token}")?;
}
}
Ok(ctxs)
} else {
Self::send_log("token not found")?;
send_log("token not found")?;
Ok(vec![])
}
}

View file

@ -1,19 +1,19 @@
use erg_common::traits::NoTypeDisplay;
use erg_compiler::ty::HasType;
use lsp_types::Position;
use serde::Deserialize;
use serde_json::json;
use serde_json::Value;
use erg_common::traits::{DequeStream, Locational, NoTypeDisplay};
use erg_compiler::artifact::BuildRunnable;
use erg_compiler::erg_parser::token::{Token, TokenKind};
use erg_compiler::hir::Expr;
use erg_compiler::ty::{HasType, ParamTy};
use lsp_types::{
ParameterInformation, ParameterLabel, SignatureHelp, SignatureHelpParams, SignatureInformation,
Url,
ParameterInformation, ParameterLabel, Position, SignatureHelp, SignatureHelpContext,
SignatureHelpParams, SignatureHelpTriggerKind, SignatureInformation, Url,
};
use crate::server::{ELSResult, Server};
use crate::server::{send, send_log, ELSResult, Server};
use crate::util;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -26,7 +26,7 @@ pub enum Trigger {
impl From<String> for Trigger {
fn from(s: String) -> Self {
match s.as_str() {
"(" | ")" => Trigger::Paren,
"(" => Trigger::Paren,
"," => Trigger::Comma,
"|" => Trigger::VBar,
_ => unreachable!(),
@ -34,12 +34,24 @@ impl From<String> for Trigger {
}
}
fn get_end(start: usize, pt: &ParamTy) -> usize {
start + pt.name().unwrap().len() + 2 + pt.typ().to_string().len()
}
impl<Checker: BuildRunnable> Server<Checker> {
pub(crate) fn show_signature_help(&mut self, msg: &Value) -> ELSResult<()> {
Self::send_log(format!("signature help requested: {msg}"))?;
send_log(format!("signature help requested: {msg}"))?;
let params = SignatureHelpParams::deserialize(&msg["params"])?;
let uri = util::normalize_url(params.text_document_position_params.text_document.uri);
let pos = params.text_document_position_params.position;
if params.context.as_ref().map(|ctx| &ctx.trigger_kind)
== Some(&SignatureHelpTriggerKind::CONTENT_CHANGE)
{
let help = self.resend_help(&uri, pos, params.context.as_ref().unwrap());
return send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": help }),
);
}
let trigger = params
.context
.and_then(|c| c.trigger_character)
@ -49,79 +61,131 @@ impl<Checker: BuildRunnable> Server<Checker> {
Some(Trigger::Comma) => self.get_continuous_help(&uri, pos),
Some(Trigger::VBar) | None => None,
};
Self::send(
&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }),
)
send(&json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }))
}
fn get_first_help(&self, uri: &Url, pos: Position) -> Option<SignatureHelp> {
if let Some(token) = self.file_cache.get_token_relatively(uri, pos, -1).ok()? {
fn nth(&self, uri: &Url, args_loc: erg_common::error::Location, token: &Token) -> usize {
// we should use the latest commas
let commas = self
.file_cache
.get_token_stream(uri)
.unwrap()
.iter()
.skip_while(|&tk| tk.loc() < args_loc)
.filter(|tk| tk.is(TokenKind::Comma) && args_loc.ln_end() >= tk.ln_begin())
.collect::<Vec<_>>();
let argc = commas.len();
commas
.iter()
.position(|c| c.col_end().unwrap() >= token.col_end().unwrap())
.unwrap_or(argc) // `commas.col_end() < token.col_end()` means the token is the last argument
}
fn resend_help(
&mut self,
uri: &Url,
pos: Position,
ctx: &SignatureHelpContext,
) -> Option<SignatureHelp> {
if let Some(token) = self.file_cache.get_token(uri, pos) {
send_log(format!("token: {token}")).unwrap();
if let Some(Expr::Call(call)) = &self.current_sig {
if call.ln_begin() > token.ln_begin() || call.ln_end() < token.ln_end() {
self.current_sig = None;
return None;
}
let nth = self.nth(uri, call.args.loc(), &token) as u32;
return self.make_sig_help(call.obj.as_ref(), nth);
}
} else {
send_log("lex error occurred").unwrap();
}
ctx.active_signature_help.clone()
}
fn get_first_help(&mut self, uri: &Url, pos: Position) -> Option<SignatureHelp> {
if let Some(token) = self.file_cache.get_token_relatively(uri, pos, -2).ok()? {
// send_log(format!("token before `(`: {token}")).unwrap();
if let Some(visitor) = self.get_visitor(uri) {
match visitor.get_min_expr(&token) {
Some(Expr::Call(call)) => {
let sig_t = call.signature_t().unwrap();
Self::send_log(format!("t: {sig_t}")).unwrap();
Some(Expr::Call(_call)) => {
// let sig_t = call.signature_t().unwrap();
// send_log(format!("call: {call}")).unwrap();
}
Some(Expr::Accessor(acc)) => {
let sig_t = acc.ref_t();
return self.make_sig_help(acc, 0);
}
_ => {}
}
}
} else {
send_log("lex error occurred").unwrap();
}
None
}
fn get_continuous_help(&mut self, uri: &Url, pos: Position) -> Option<SignatureHelp> {
if let Some(comma) = self.file_cache.get_token_relatively(uri, pos, -1).ok()? {
send_log(format!("comma: {comma}")).unwrap();
if let Some(visitor) = self.get_visitor(uri) {
#[allow(clippy::single_match)]
match visitor.get_min_expr(&comma) {
Some(Expr::Call(call)) => {
let nth = self.nth(uri, call.args.loc(), &comma) as u32 + 1;
let help = self.make_sig_help(call.obj.as_ref(), nth);
self.current_sig = Some(Expr::Call(call.clone()));
return help;
}
_ => {}
}
} else {
// send_log("visitor not found").unwrap();
}
} else {
send_log("lex error occurred").unwrap();
}
None
}
fn make_sig_help<S: HasType + NoTypeDisplay>(
&self,
sig: &S,
nth: u32,
) -> Option<SignatureHelp> {
let sig_t = sig.ref_t();
let mut parameters = vec![];
let label = format!("{}: {sig_t}", sig.to_string_notype());
for nd_param in sig_t.non_default_params()? {
let start = label.find(&nd_param.name().unwrap()[..]).unwrap();
let end = get_end(start, nd_param);
let param_info = ParameterInformation {
label: ParameterLabel::Simple(
nd_param.name().map_or("".to_string(), |s| s.to_string()),
),
label: ParameterLabel::LabelOffsets([start as u32, end as u32]),
documentation: None, //Some(Documentation::String(nd_param.typ().to_string())),
};
parameters.push(param_info);
}
if let Some(var_params) = sig_t.var_params() {
// var_params.name().is_none() => skip
if let Some(start) = label.find(var_params.name().map_or("#", |s| &s[..])) {
let end = get_end(start, var_params);
let param_info = ParameterInformation {
label: ParameterLabel::Simple(
var_params.name().map_or("".to_string(), |s| s.to_string()),
),
label: ParameterLabel::LabelOffsets([start as u32, end as u32]),
documentation: None, //Some(Documentation::String(var_params.typ().to_string())),
};
parameters.push(param_info);
}
}
let nth = (parameters.len() as u32 - 1).min(nth);
let info = SignatureInformation {
label: format!("{}: {sig_t}", acc.to_string_notype()),
label,
documentation: None,
parameters: Some(parameters),
active_parameter: Some(0),
active_parameter: Some(nth),
};
return Some(SignatureHelp {
Some(SignatureHelp {
signatures: vec![info],
active_parameter: None,
active_signature: None,
});
}
Some(other) => {
Self::send_log(format!("other: {other}")).unwrap();
}
_ => {}
}
}
} else {
Self::send_log("lex error occurred").unwrap();
}
None
}
fn get_continuous_help(&self, uri: &Url, pos: Position) -> Option<SignatureHelp> {
if let Some(token) = self.file_cache.get_token(uri, pos) {
Self::send_log(format!("comma?: {token}")).unwrap();
if let Some(visitor) = self.get_visitor(uri) {
#[allow(clippy::single_match)]
match visitor.get_min_expr(&token) {
Some(Expr::Call(call)) => {
Self::send_log(format!("call: {call}")).unwrap();
}
_ => {}
}
}
} else {
Self::send_log("lex error occurred").unwrap();
}
None
})
}
}

View file

@ -25,6 +25,10 @@ pub fn loc_to_pos(loc: erg_common::error::Location) -> Option<Position> {
Some(start)
}
pub fn _pos_to_loc(pos: Position) -> erg_common::error::Location {
erg_common::error::Location::range(pos.line + 1, pos.character - 1, pos.line + 1, pos.character)
}
pub fn pos_in_loc<L: Locational>(loc: &L, pos: Position) -> bool {
let ln_begin = loc.ln_begin().unwrap_or(0);
let ln_end = loc.ln_end().unwrap_or(0);

View file

@ -2799,13 +2799,10 @@ impl PyCodeGenerator {
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let vi = VarInfo::parameter(new_first_param.typ().clone(), ident.vi.def_loc.clone());
let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![self_param, param], None, vec![], None);
let params = Params::new(vec![self_param, param], None, vec![], None, vec![]);
(param_name, params)
} else {
(
"_".into(),
Params::new(vec![self_param], None, vec![], None),
)
("_".into(), Params::single(self_param))
};
let bounds = TypeBoundSpecs::empty();
let subr_sig = SubrSignature::new(ident, bounds, params, sig.t_spec().cloned());
@ -2883,22 +2880,22 @@ impl PyCodeGenerator {
let raw =
erg_parser::ast::NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
let bounds = TypeBoundSpecs::empty();
let sig = SubrSignature::new(ident, bounds, params, sig.t_spec().cloned());
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name),
line,
)));
let call = class_new.call_expr(Args::new(vec![arg], None, vec![], None));
let call = class_new.call_expr(Args::single(arg));
let block = Block::new(vec![call]);
let body = DefBody::new(EQUAL, block, DefId(0));
self.emit_subr_def(Some(class_ident.inspect()), sig, body);
} else {
let params = Params::new(vec![], None, vec![], None);
let params = Params::empty();
let bounds = TypeBoundSpecs::empty();
let sig = SubrSignature::new(ident, bounds, params, sig.t_spec().cloned());
let call = class_new.call_expr(Args::new(vec![], None, vec![], None));
let call = class_new.call_expr(Args::empty());
let block = Block::new(vec![call]);
let body = DefBody::new(EQUAL, block, DefId(0));
self.emit_subr_def(Some(class_ident.inspect()), sig, body);

View file

@ -947,7 +947,7 @@ impl Context {
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], input, namespace)
.map_err(|errs| {
.map_err(|(_, errs)| {
let Some(op_ident ) = option_enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_))) else {
return errs;
};
@ -981,7 +981,7 @@ impl Context {
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, vi));
self.get_call_t(&op, &None, args, &[], input, namespace)
.map_err(|errs| {
.map_err(|(_, errs)| {
let Some(op_ident) = option_enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_))) else {
return errs;
};
@ -1575,41 +1575,62 @@ impl Context {
kw_args: &[hir::KwArg],
input: &Input,
namespace: &Str,
) -> TyCheckResult<VarInfo> {
) -> Result<VarInfo, (Option<VarInfo>, TyCheckErrors)> {
if let hir::Expr::Accessor(hir::Accessor::Ident(local)) = obj {
if local.vis().is_private() {
match &local.inspect()[..] {
"match" => {
return self.get_match_call_t(SubrKind::Func, pos_args, kw_args);
return self
.get_match_call_t(SubrKind::Func, pos_args, kw_args)
.map_err(|errs| (None, errs));
}
"match!" => {
return self.get_match_call_t(SubrKind::Proc, pos_args, kw_args);
return self
.get_match_call_t(SubrKind::Proc, pos_args, kw_args)
.map_err(|errs| (None, errs));
}
_ => {}
}
}
}
let found = self.search_callee_info(obj, attr_name, input, namespace)?;
let found = self
.search_callee_info(obj, attr_name, input, namespace)
.map_err(|err| (None, TyCheckErrors::from(err)))?;
log!(
"Found:\ncallee: {obj}{}\nfound: {found}",
fmt_option!(pre ".", attr_name.as_ref().map(|ident| &ident.name))
);
let instance = self.instantiate(found.t, obj)?;
let instance = self
.instantiate(found.t.clone(), obj)
.map_err(|errs| (Some(found.clone()), errs))?;
log!(
"Instantiated:\ninstance: {instance}\npos_args: ({})\nkw_args: ({})",
fmt_slice(pos_args),
fmt_slice(kw_args)
);
let instance = match self.substitute_call(obj, attr_name, &instance, pos_args, kw_args)? {
let instance = match self
.substitute_call(obj, attr_name, &instance, pos_args, kw_args)
.map_err(|errs| (Some(found.clone()), errs))?
{
SubstituteResult::Ok => instance,
SubstituteResult::__Call__(__call__) => __call__,
SubstituteResult::Coerced(coerced) => coerced,
};
debug_assert!(!instance.is_quantified_subr());
log!(info "Substituted:\ninstance: {instance}");
let res = self.eval_t_params(instance, self.level, obj)?;
let res = self
.eval_t_params(instance, self.level, obj)
.map_err(|errs| (Some(found.clone()), errs))?;
log!(info "Params evaluated:\nres: {res}\n");
self.propagate(&res, obj)?;
self.propagate(&res, obj).map_err(|errs| {
(
Some(VarInfo {
t: res.clone(),
..found.clone()
}),
errs,
)
})?;
log!(info "Propagated:\nres: {res}\n");
let res = VarInfo { t: res, ..found };
Ok(res)

View file

@ -153,7 +153,7 @@ impl ASTLowerer {
}
fn fake_lower_args(&self, args: ast::Args) -> LowerResult<hir::Args> {
let (pos_args_, var_args_, kw_args_, paren) = args.deconstruct();
let (pos_args_, var_args_, kw_args_, paren, commas) = args.deconstruct();
let mut pos_args = vec![];
for arg in pos_args_.into_iter() {
let arg = self.fake_lower_expr(arg.expr)?;
@ -171,7 +171,7 @@ impl ASTLowerer {
let expr = self.fake_lower_expr(kw_arg.expr)?;
kw_args.push(hir::KwArg::new(kw_arg.keyword, expr));
}
let args = hir::Args::new(pos_args, var_args, kw_args, paren);
let args = hir::Args::new(pos_args, var_args, kw_args, paren, commas);
Ok(args)
}
@ -206,12 +206,12 @@ impl ASTLowerer {
}
ast::Array::Normal(arr) => {
let mut elems = Vec::new();
let (elems_, ..) = arr.elems.deconstruct();
let (elems_, .., commas) = arr.elems.deconstruct();
for elem in elems_.into_iter() {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], None);
let elems = hir::Args::new(elems, None, vec![], None, commas);
Ok(hir::Array::Normal(hir::NormalArray::new(
arr.l_sqbr,
arr.r_sqbr,
@ -232,12 +232,12 @@ impl ASTLowerer {
match tup {
ast::Tuple::Normal(tup) => {
let mut elems = Vec::new();
let (elems_, _, _, paren) = tup.elems.deconstruct();
let (elems_, _, _, paren, commas) = tup.elems.deconstruct();
for elem in elems_.into_iter() {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], paren);
let elems = hir::Args::pos_only(elems, paren, commas);
Ok(hir::Tuple::Normal(hir::NormalTuple::new(elems)))
}
}
@ -290,7 +290,7 @@ impl ASTLowerer {
let elem = self.fake_lower_expr(elem.expr)?;
elems.push(hir::PosArg::new(elem));
}
let elems = hir::Args::new(elems, None, vec![], None);
let elems = hir::Args::pos_only(elems, None, vec![]);
Ok(hir::Set::Normal(hir::NormalSet::new(
set.l_brace,
set.r_brace,
@ -334,7 +334,7 @@ impl ASTLowerer {
}
fn fake_lower_params(&self, params: ast::Params) -> LowerResult<hir::Params> {
let (non_defaults_, var_params_, defaults_, parens) = params.deconstruct();
let (non_defaults_, var_params_, defaults_, parens, commas) = params.deconstruct();
let mut non_defaults = vec![];
for non_default_ in non_defaults_.into_iter() {
let non_default =
@ -355,7 +355,13 @@ impl ASTLowerer {
let default = hir::DefaultParamSignature::new(sig, default_val);
defaults.push(default);
}
Ok(hir::Params::new(non_defaults, var_args, defaults, parens))
Ok(hir::Params::new(
non_defaults,
var_args,
defaults,
parens,
commas,
))
}
fn fake_lower_block(&self, block: ast::Block) -> LowerResult<hir::Block> {

View file

@ -169,6 +169,7 @@ pub struct Args {
pub var_args: Option<Box<PosArg>>,
pub kw_args: Vec<KwArg>,
pub paren: Option<(Token, Token)>,
pub commas: Vec<Token>,
}
impl NestedDisplay for Args {
@ -244,26 +245,35 @@ impl Args {
var_args: Option<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
commas,
}
}
pub fn values(exprs: Vec<Expr>, paren: Option<(Token, Token)>) -> Self {
Self::new(
exprs.into_iter().map(PosArg::new).collect(),
None,
vec![],
paren,
)
pub fn values(exprs: Vec<Expr>, paren: Option<(Token, Token)>, commas: Vec<Token>) -> Self {
Self::pos_only(exprs.into_iter().map(PosArg::new).collect(), paren, commas)
}
pub fn single(pos_arg: PosArg) -> Self {
Self::pos_only(vec![pos_arg], None, vec![])
}
pub fn pos_only(
pos_args: Vec<PosArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self::new(pos_args, None, vec![], paren, commas)
}
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
Self::new(vec![], None, vec![], None, vec![])
}
#[inline]
@ -1673,6 +1683,7 @@ pub struct Params {
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
pub commas: Vec<Token>,
}
impl fmt::Display for Params {
@ -1742,18 +1753,28 @@ type RefRawParams<'a> = (
impl Params {
pub const fn new(
non_defaults: Vec<NonDefaultParamSignature>,
var_args: Option<Box<NonDefaultParamSignature>>,
var_params: Option<Box<NonDefaultParamSignature>>,
defaults: Vec<DefaultParamSignature>,
parens: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self {
non_defaults,
var_params: var_args,
var_params,
defaults,
parens,
commas,
}
}
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None, vec![])
}
pub fn single(sig: NonDefaultParamSignature) -> Self {
Self::new(vec![sig], None, vec![], None, vec![])
}
pub const fn ref_deconstruct(&self) -> RefRawParams {
(
&self.non_defaults,

View file

@ -326,7 +326,7 @@ impl<'a> Linker<'a> {
let code = Expr::Code(Block::new(Vec::from(hir.module)));
let module_type =
Expr::Accessor(Accessor::private_with_line(Str::ever("#ModuleType"), line));
let args = Args::new(vec![PosArg::new(mod_name.clone())], None, vec![], None);
let args = Args::single(PosArg::new(mod_name.clone()));
let block = Block::new(vec![module_type.call_expr(args)]);
let tmp = Identifier::private_with_line(Str::from(fresh_varname()), line);
let mod_def = Expr::Def(Def::new(
@ -338,19 +338,14 @@ impl<'a> Linker<'a> {
let m_dict = module.clone().attr_expr(__dict__);
let locals = Expr::Accessor(Accessor::public_with_line(Str::ever("locals"), line));
let locals_call = locals.call_expr(Args::empty());
let args = Args::new(vec![PosArg::new(locals_call)], None, vec![], None);
let args = Args::single(PosArg::new(locals_call));
let mod_update = Expr::Call(Call::new(
m_dict.clone(),
Some(Identifier::public("update")),
args,
));
let exec = Expr::Accessor(Accessor::public_with_line(Str::ever("exec"), line));
let args = Args::new(
vec![PosArg::new(code), PosArg::new(m_dict)],
None,
vec![],
None,
);
let args = Args::pos_only(vec![PosArg::new(code), PosArg::new(m_dict)], None, vec![]);
let exec_code = exec.call_expr(args);
let compound = Block::new(vec![mod_def, mod_update, exec_code, module]);
*expr = Expr::Compound(compound);

View file

@ -248,9 +248,9 @@ impl ASTLowerer {
log!(info "entered {}({array})", fn_name!());
let allow_cast = true;
let mut new_array = vec![];
let (elems, _) = array.elems.into_iters();
let (elems, .., commas) = array.elems.deconstruct();
let mut union = Type::Never;
for elem in elems {
for elem in elems.into_iter() {
let elem = self.lower_expr(elem.expr)?;
let union_ = self.module.context.union(&union, elem.ref_t());
if let Some((l, r)) = union_.union_types() {
@ -291,7 +291,7 @@ impl ASTLowerer {
array.l_sqbr,
array.r_sqbr,
elem_t,
hir::Args::values(new_array, None),
hir::Args::values(new_array, None, commas),
))
}
@ -355,12 +355,14 @@ impl ASTLowerer {
fn lower_normal_tuple(&mut self, tuple: ast::NormalTuple) -> LowerResult<hir::NormalTuple> {
log!(info "entered {}({tuple})", fn_name!());
let mut new_tuple = vec![];
let (elems, .., paren) = tuple.elems.deconstruct();
let (elems, .., paren, commas) = tuple.elems.deconstruct();
for elem in elems {
let elem = self.lower_expr(elem.expr)?;
new_tuple.push(elem);
}
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
Ok(hir::NormalTuple::new(hir::Args::values(
new_tuple, paren, commas,
)))
}
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
@ -399,7 +401,7 @@ impl ASTLowerer {
fn lower_normal_set(&mut self, set: ast::NormalSet) -> LowerResult<hir::NormalSet> {
log!(info "entered {}({set})", fn_name!());
let (elems, _) = set.elems.into_iters();
let (elems, .., commas) = set.elems.deconstruct();
let mut union = Type::Never;
let mut new_set = vec![];
for elem in elems {
@ -458,7 +460,7 @@ impl ASTLowerer {
}
Ok(normal_set)
*/
let elems = hir::Args::values(new_set, None);
let elems = hir::Args::values(new_set, None, commas);
// check if elem_t is Eq
if let Err(errs) = self
.module
@ -720,12 +722,13 @@ impl ASTLowerer {
}
fn lower_args(&mut self, args: ast::Args, errs: &mut LowerErrors) -> hir::Args {
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
let (pos_args, var_args, kw_args, paren, commas) = args.deconstruct();
let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
None,
Vec::with_capacity(kw_args.len()),
paren,
commas,
);
for arg in pos_args.into_iter() {
match self.lower_expr(arg.expr) {
@ -761,6 +764,8 @@ impl ASTLowerer {
hir_args
}
/// returning `Ok(call)` does not mean the call is valid, just means it is syntactically valid
/// `ASTLowerer` is designed to cause as little information loss in HIR as possible
pub(crate) fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name));
if let Some(name) = call.obj.get_name() {
@ -810,10 +815,10 @@ impl ASTLowerer {
&self.module.context.name,
) {
Ok(vi) => vi,
Err(es) => {
Err((vi, es)) => {
self.module.context.higher_order_caller.pop();
errs.extend(es);
return Err(errs);
vi.unwrap_or(VarInfo::ILLEGAL.clone())
}
};
let attr_name = if let Some(attr_name) = call.attr_name {
@ -877,11 +882,8 @@ impl ASTLowerer {
}
}
}
if errs.is_empty() {
self.errs.extend(errs);
Ok(call)
} else {
Err(errs)
}
}
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
@ -903,15 +905,21 @@ impl ASTLowerer {
pack.connector.col_begin,
)),
);
let vi = self.module.context.get_call_t(
let vi = match self.module.context.get_call_t(
&class,
&Some(attr_name.clone()),
&args,
&[],
&self.cfg.input,
&self.module.context.name,
)?;
let args = hir::Args::new(args, None, vec![], None);
) {
Ok(vi) => vi,
Err((vi, errs)) => {
self.errs.extend(errs);
vi.unwrap_or(VarInfo::ILLEGAL.clone())
}
};
let args = hir::Args::pos_only(args, None, vec![]);
let attr_name = hir::Identifier::new(attr_name.dot, attr_name.name, None, vi);
Ok(hir::Call::new(class, Some(attr_name), args))
}
@ -983,6 +991,7 @@ impl ASTLowerer {
hir_var_params,
hir_defaults,
params.parens,
params.commas,
);
Ok(hir_params)
}

View file

@ -718,6 +718,7 @@ pub enum Type {
param_ts: Vec<Type>,
return_t: Box<Type>,
},
// Overloaded(Vec<Type>),
Record(Dict<Field, Type>), // e.g. {x = Int}
// e.g. {T -> T | T: Type}, {I: Int | I > 0}, {S | N: Nat; S: Str N; N > 1}
// 区間型と列挙型は篩型に変換される

View file

@ -161,7 +161,9 @@ pub struct Args {
pos_args: Vec<PosArg>,
pub(crate) var_args: Option<Box<PosArg>>,
kw_args: Vec<KwArg>,
// these are for ELS
pub paren: Option<(Token, Token)>,
pub commas: Vec<Token>,
}
impl NestedDisplay for Args {
@ -199,21 +201,31 @@ impl Args {
var_args: Option<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
commas,
}
}
pub fn pos_only(pos_args: Vec<PosArg>, paren: Option<(Token, Token)>) -> Self {
Self::new(pos_args, None, vec![], paren)
pub fn pos_only(
pos_arg: Vec<PosArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self::new(pos_arg, None, vec![], paren, commas)
}
pub fn single(pos_args: PosArg) -> Self {
Self::pos_only(vec![pos_args], None, vec![])
}
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
Self::new(vec![], None, vec![], None, vec![])
}
// for replacing to hir::Args
@ -225,12 +237,14 @@ impl Args {
Option<PosArg>,
Vec<KwArg>,
Option<(Token, Token)>,
Vec<Token>,
) {
(
self.pos_args,
self.var_args.map(|x| *x),
self.kw_args,
self.paren,
self.commas,
)
}
@ -294,6 +308,14 @@ impl Args {
self.kw_args.push(arg);
}
pub fn push_comma(&mut self, comma: Token) {
self.commas.push(comma);
}
pub fn set_parens(&mut self, paren: (Token, Token)) {
self.paren = Some(paren);
}
pub fn get_left_or_key(&self, key: &str) -> Option<&Expr> {
if !self.pos_args.is_empty() {
self.pos_args.get(0).map(|a| &a.expr)
@ -1894,6 +1916,7 @@ pub struct ConstArgs {
var_args: Option<Box<ConstPosArg>>,
kw_args: Vec<ConstKwArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
}
impl NestedDisplay for ConstArgs {
@ -1928,17 +1951,23 @@ impl ConstArgs {
var_args: Option<ConstPosArg>,
kw_args: Vec<ConstKwArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
commas,
}
}
pub fn pos_only(pos_args: Vec<ConstPosArg>, paren: Option<(Token, Token)>) -> Self {
Self::new(pos_args, None, vec![], paren)
pub fn pos_only(
pos_args: Vec<ConstPosArg>,
paren: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self::new(pos_args, None, vec![], paren, commas)
}
#[allow(clippy::type_complexity)]
@ -1949,17 +1978,19 @@ impl ConstArgs {
Option<ConstPosArg>,
Vec<ConstKwArg>,
Option<(Token, Token)>,
Vec<Token>,
) {
(
self.pos_args,
self.var_args.map(|x| *x),
self.kw_args,
self.paren,
self.commas,
)
}
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
Self::new(vec![], None, vec![], None, vec![])
}
pub fn is_empty(&self) -> bool {
@ -1992,7 +2023,7 @@ impl ConstArgs {
}
pub fn downcast(self) -> Args {
let (pos_args, var_args, kw_args, paren) = self.deconstruct();
let (pos_args, var_args, kw_args, paren, commas) = self.deconstruct();
Args::new(
pos_args
.into_iter()
@ -2005,6 +2036,7 @@ impl ConstArgs {
.map(|arg| KwArg::new(arg.keyword, None, arg.expr.downcast()))
.collect(),
paren,
commas,
)
}
}
@ -2417,6 +2449,7 @@ impl TypeSpec {
None,
vec![],
None,
vec![],
))
}
}
@ -3311,6 +3344,7 @@ pub struct Params {
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub parens: Option<(Token, Token)>,
pub commas: Vec<Token>,
}
impl fmt::Display for Params {
@ -3354,6 +3388,7 @@ type RawParams = (
Option<Box<NonDefaultParamSignature>>,
Vec<DefaultParamSignature>,
Option<(Token, Token)>,
Vec<Token>,
);
impl Params {
@ -3362,21 +3397,28 @@ impl Params {
var_params: Option<NonDefaultParamSignature>,
defaults: Vec<DefaultParamSignature>,
parens: Option<(Token, Token)>,
commas: Vec<Token>,
) -> Self {
Self {
non_defaults,
var_params: var_params.map(Box::new),
defaults,
parens,
commas,
}
}
pub fn single(non_default: NonDefaultParamSignature) -> Self {
Self::new(vec![non_default], None, vec![], None, vec![])
}
pub fn deconstruct(self) -> RawParams {
(
self.non_defaults,
self.var_params,
self.defaults,
self.parens,
self.commas,
)
}
@ -3522,7 +3564,7 @@ impl LambdaSignature {
pub fn do_sig(do_symbol: &Token) -> Self {
let parens = Some((do_symbol.clone(), do_symbol.clone()));
Self::new(
Params::new(vec![], None, vec![], parens),
Params::new(vec![], None, vec![], parens, vec![]),
None,
TypeBoundSpecs::empty(),
)

View file

@ -211,7 +211,7 @@ impl Parser {
let mut vars = Vars::empty();
match tuple {
Tuple::Normal(tup) => {
let (pos_args, _var_args, _kw_args, paren) = tup.elems.deconstruct();
let (pos_args, _var_args, _kw_args, paren, _commas) = tup.elems.deconstruct();
for arg in pos_args {
let sig = self
.convert_rhs_to_sig(arg.expr)
@ -321,7 +321,7 @@ impl Parser {
) -> ParseResult<TypeBoundSpecs> {
debug_call_info!(self);
let mut bounds = vec![];
let (pos_args, _var_args, _kw_args, _paren) = type_args.args.deconstruct();
let (pos_args, _var_args, _kw_args, _paren, _commas) = type_args.args.deconstruct();
for arg in pos_args.into_iter() {
let bound = self
.convert_type_arg_to_bound(arg)
@ -357,8 +357,8 @@ impl Parser {
pub(crate) fn convert_args_to_params(&mut self, args: Args) -> ParseResult<Params> {
debug_call_info!(self);
let (pos_args, var_args, kw_args, parens) = args.deconstruct();
let mut params = Params::new(vec![], None, vec![], parens);
let (pos_args, var_args, kw_args, parens, commas) = args.deconstruct();
let mut params = Params::new(vec![], None, vec![], parens, commas);
for (i, arg) in pos_args.into_iter().enumerate() {
let nd_param = self
.convert_pos_arg_to_non_default_param(arg, i == 0)
@ -519,7 +519,7 @@ impl Parser {
for arg in arr.elems.into_iters().0 {
params.push(self.convert_pos_arg_to_non_default_param(arg, false)?);
}
let params = Params::new(params, None, vec![], None);
let params = Params::new(params, None, vec![], None, vec![]);
debug_exit_info!(self);
Ok(ParamArrayPattern::new(arr.l_sqbr, params, arr.r_sqbr))
}
@ -598,7 +598,7 @@ impl Parser {
match tuple {
Tuple::Normal(tup) => {
let mut params = vec![];
let (elems, var_args, _, parens) = tup.elems.deconstruct();
let (elems, var_args, _, parens, commas) = tup.elems.deconstruct();
for arg in elems.into_iter() {
params.push(self.convert_pos_arg_to_non_default_param(arg, false)?);
}
@ -608,7 +608,7 @@ impl Parser {
} else {
None
};
let params = Params::new(params, var_params, vec![], parens);
let params = Params::new(params, var_params, vec![], parens, commas);
debug_exit_info!(self);
Ok(ParamTuplePattern::new(params))
}
@ -634,14 +634,14 @@ impl Parser {
match rhs {
Expr::Literal(lit) => {
let param = NonDefaultParamSignature::new(ParamPattern::Lit(lit), None);
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
Expr::Accessor(accessor) => {
let param = self
.convert_accessor_to_param_sig(accessor)
.map_err(|_| self.stack_dec(fn_name!()))?;
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
debug_exit_info!(self);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
@ -657,7 +657,7 @@ impl Parser {
.convert_array_to_param_array_pat(array)
.map_err(|_| self.stack_dec(fn_name!()))?;
let param = NonDefaultParamSignature::new(ParamPattern::Array(arr), None);
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
debug_exit_info!(self);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
@ -666,7 +666,7 @@ impl Parser {
.convert_record_to_param_record_pat(record)
.map_err(|_| self.stack_dec(fn_name!()))?;
let param = NonDefaultParamSignature::new(ParamPattern::Record(rec), None);
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
debug_exit_info!(self);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
@ -683,7 +683,7 @@ impl Parser {
let param = self
.convert_rhs_to_param(*exprs.next().unwrap(), false)
.map_err(|_| self.stack_dec(fn_name!()))?;
let params = Params::new(vec![], Some(param), vec![], None);
let params = Params::new(vec![], Some(param), vec![], None, vec![]);
debug_exit_info!(self);
Ok(LambdaSignature::new(params, None, TypeBoundSpecs::empty()))
}
@ -731,8 +731,8 @@ impl Parser {
debug_call_info!(self);
match tuple {
Tuple::Normal(tup) => {
let (pos_args, var_args, kw_args, paren) = tup.elems.deconstruct();
let mut params = Params::new(vec![], None, vec![], paren);
let (pos_args, var_args, kw_args, paren, commas) = tup.elems.deconstruct();
let mut params = Params::new(vec![], None, vec![], paren, commas);
for (i, arg) in pos_args.into_iter().enumerate() {
let param = self
.convert_pos_arg_to_non_default_param(arg, i == 0)
@ -767,7 +767,7 @@ impl Parser {
.map_err(|_| self.stack_dec(fn_name!()))?;
debug_exit_info!(self);
Ok(LambdaSignature::new(
Params::new(vec![sig], None, vec![], None),
Params::single(sig),
None,
TypeBoundSpecs::empty(),
))

View file

@ -62,7 +62,7 @@ impl Desugarer {
}
fn desugar_args(mut desugar: impl FnMut(Expr) -> Expr, args: Args) -> Args {
let (pos_args, var_args, kw_args, paren) = args.deconstruct();
let (pos_args, var_args, kw_args, paren, commas) = args.deconstruct();
let pos_args = pos_args
.into_iter()
.map(|arg| PosArg::new(desugar(arg.expr)))
@ -74,7 +74,7 @@ impl Desugarer {
KwArg::new(arg.keyword, arg.t_spec, desugar(arg.expr)) // TODO: t_spec
})
.collect();
Args::new(pos_args, var_args, kw_args, paren)
Args::new(pos_args, var_args, kw_args, paren, commas)
}
fn perform_desugar_acc(mut desugar: impl FnMut(Expr) -> Expr, acc: Accessor) -> Accessor {
@ -145,12 +145,12 @@ impl Desugarer {
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _, _) = arr.elems.deconstruct();
let (elems, _, _, _, commas) = arr.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.collect();
let elems = Args::new(elems, None, vec![], None);
let elems = Args::pos_only(elems, None, commas);
let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems);
Expr::Array(Array::Normal(arr))
}
@ -175,24 +175,24 @@ impl Desugarer {
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let (elems, _, _, paren) = tup.elems.deconstruct();
let (elems, _, _, paren, commas) = tup.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.collect();
let new_tup = Args::new(elems, None, vec![], paren);
let new_tup = Args::pos_only(elems, paren, commas);
let tup = NormalTuple::new(new_tup);
Expr::Tuple(Tuple::Normal(tup))
}
},
Expr::Set(set) => match set {
astSet::Normal(set) => {
let (elems, _, _, _) = set.elems.deconstruct();
let (elems, _, _, _, commas) = set.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(desugar(elem.expr)))
.collect();
let elems = Args::new(elems, None, vec![], None);
let elems = Args::pos_only(elems, None, commas);
let set = NormalSet::new(set.l_brace, set.r_brace, elems);
Expr::Set(astSet::Normal(set))
}
@ -359,7 +359,7 @@ impl Desugarer {
));
let param =
NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let params = Params::new(vec![param], None, vec![], None);
let params = Params::single(param);
let sig = Signature::Subr(SubrSignature::new(
set! {},
name,
@ -425,6 +425,7 @@ impl Desugarer {
PosArg::new(Expr::Lambda(second_branch)),
],
None,
vec![],
);
let call = match_symbol.call(args);
(call, return_t_spec)
@ -781,7 +782,7 @@ impl Desugarer {
kind: TokenKind::RBrace,
..lit.token
};
let args = Args::pos_only(vec![PosArg::new(Expr::Literal(lit))], None);
let args = Args::single(PosArg::new(Expr::Literal(lit)));
Expr::from(NormalSet::new(l_brace, r_brace, args))
}
@ -841,7 +842,7 @@ impl Desugarer {
..lit.token
};
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
let args = Args::pos_only(vec![PosArg::new(Expr::Literal(lit))], None);
let args = Args::single(PosArg::new(Expr::Literal(lit)));
let t_spec_as_expr = Expr::from(NormalSet::new(l_brace, r_brace, args));
let t_spec = TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr);
param.t_spec = Some(t_spec);
@ -879,6 +880,7 @@ impl Desugarer {
let t_spec_as_expr = Expr::from(NormalTuple::new(Args::pos_only(
ty_exprs,
tup.elems.parens.clone(),
tup.elems.commas.clone(),
)));
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
@ -1048,6 +1050,7 @@ impl Desugarer {
let t_spec_as_expr = Expr::from(NormalTuple::new(Args::pos_only(
ty_exprs,
tup.elems.parens.clone(),
tup.elems.commas.clone(),
)));
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
@ -1218,10 +1221,7 @@ impl Desugarer {
match acc {
// x[y] => x.__getitem__(y)
Accessor::Subscr(subscr) => {
let args = Args::pos_only(
vec![PosArg::new(Self::rec_desugar_acc(*subscr.index))],
None,
);
let args = Args::single(PosArg::new(Self::rec_desugar_acc(*subscr.index)));
let line = subscr.obj.ln_begin().unwrap();
let call = Call::new(
Self::rec_desugar_acc(*subscr.obj),
@ -1236,7 +1236,7 @@ impl Desugarer {
}
// x.0 => x.__Tuple_getitem__(0)
Accessor::TupleAttr(tattr) => {
let args = Args::pos_only(vec![PosArg::new(Expr::Literal(tattr.index))], None);
let args = Args::single(PosArg::new(Expr::Literal(tattr.index)));
let line = tattr.obj.ln_begin().unwrap();
let call = Call::new(
Self::rec_desugar_acc(*tattr.obj),

View file

@ -560,7 +560,7 @@ impl Parser {
let first = self
.try_reduce_elem()
.map_err(|_| self.stack_dec(fn_name!()))?;
let mut elems = Args::pos_only(vec![first], None);
let mut elems = Args::single(first);
match self.peek_kind() {
Some(Semi) => {
self.lpop();
@ -691,11 +691,15 @@ impl Parser {
Some(RParen) => {
rp = Some(self.lpop());
debug_exit_info!(self);
return Ok(Args::pos_only(vec![], Some((lp.unwrap(), rp.unwrap()))));
return Ok(Args::pos_only(
vec![],
Some((lp.unwrap(), rp.unwrap())),
vec![],
));
}
Some(RBrace | RSqBr | Dedent) => {
debug_exit_info!(self);
return Ok(Args::pos_only(vec![], None));
return Ok(Args::empty());
}
Some(Newline) if style.needs_parens() => {
self.skip();
@ -714,17 +718,17 @@ impl Parser {
expr: Expr::UnaryOp(unary),
}) if unary.op.is(PreStar) => {
let pos_args = PosArg::new(unary.deconstruct().1);
Args::new(vec![], Some(pos_args), vec![], None)
Args::new(vec![], Some(pos_args), vec![], None, vec![])
}
PosOrKwArg::Pos(PosArg {
expr: Expr::TypeAscription(TypeAscription { expr, t_spec }),
}) if matches!(expr.as_ref(), Expr::UnaryOp(unary) if unary.op.is(PreStar)) => {
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
let var_args = PosArg::new(unary.deconstruct().1.type_asc_expr(t_spec));
Args::new(vec![], Some(var_args), vec![], None)
Args::new(vec![], Some(var_args), vec![], None, vec![])
}
PosOrKwArg::Pos(arg) => Args::pos_only(vec![arg], None),
PosOrKwArg::Kw(arg) => Args::new(vec![], None, vec![arg], None),
PosOrKwArg::Pos(arg) => Args::single(arg),
PosOrKwArg::Kw(arg) => Args::new(vec![], None, vec![arg], None, vec![]),
};
loop {
match self.peek_kind() {
@ -750,7 +754,7 @@ impl Parser {
self.skip();
}
Some(Comma) => {
self.skip();
args.push_comma(self.lpop());
if style.is_colon() || self.cur_is(Comma) {
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
@ -767,8 +771,7 @@ impl Parser {
}
if style.needs_parens() && self.cur_is(RParen) {
let rp = self.lpop();
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
args.set_parens((lp.unwrap(), rp));
break;
}
if !args.kw_is_empty() {
@ -807,12 +810,11 @@ impl Parser {
Some(RParen) => {
if let Some(lp) = lp {
let rp = self.lpop();
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp, rp)));
args.set_parens((lp, rp));
} else {
// e.g. f(g 1)
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, None);
let (pos_args, var_args, kw_args, _, commas) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, None, commas);
}
break;
}
@ -830,8 +832,7 @@ impl Parser {
debug_exit_info!(self);
return Err(());
}
let (pos_args, var_args, kw_args, _) = args.deconstruct();
args = Args::new(pos_args, var_args, kw_args, Some((lp.unwrap(), rp)));
args.set_parens((lp.unwrap(), rp));
}
break;
}
@ -1690,9 +1691,7 @@ impl Parser {
Signature::Var(var) => {
let mut last = def.body.block.pop().unwrap();
for deco in decos.into_iter() {
last = deco
.into_expr()
.call_expr(Args::pos_only(vec![PosArg::new(last)], None));
last = deco.into_expr().call_expr(Args::single(PosArg::new(last)));
}
def.body.block.push(last);
let expr = Expr::Def(Def::new(Signature::Var(var), def.body));
@ -1728,7 +1727,7 @@ impl Parser {
};
if self.cur_is(RParen) {
let rparen = self.lpop();
let args = Args::pos_only(vec![], Some((lparen, rparen)));
let args = Args::pos_only(vec![], Some((lparen, rparen)), vec![]);
let unit = Tuple::Normal(NormalTuple::new(args));
debug_exit_info!(self);
return Ok(Expr::Tuple(unit));
@ -2297,7 +2296,7 @@ impl Parser {
len,
)));
}
let mut args = Args::pos_only(vec![PosArg::new(first_elem)], None);
let mut args = Args::single(PosArg::new(first_elem));
loop {
match self.peek_kind() {
Some(Comma) => {
@ -2370,7 +2369,7 @@ impl Parser {
expr: Expr::UnaryOp(unary),
}) if unary.op.is(PreStar) => {
let var_args = Some(PosArg::new(unary.deconstruct().1));
Args::new(vec![], var_args, vec![], None)
Args::new(vec![], var_args, vec![], None, vec![])
}
PosOrKwArg::Pos(PosArg {
expr: Expr::TypeAscription(TypeAscription { expr, t_spec }),
@ -2378,10 +2377,10 @@ impl Parser {
let Expr::UnaryOp(unary) = *expr else { unreachable!() };
let expr = unary.deconstruct().1;
let var_args = Some(PosArg::new(expr.type_asc_expr(t_spec)));
Args::new(vec![], var_args, vec![], None)
Args::new(vec![], var_args, vec![], None, vec![])
}
PosOrKwArg::Pos(pos) => Args::pos_only(vec![pos], None),
PosOrKwArg::Kw(kw) => Args::new(vec![], None, vec![kw], None),
PosOrKwArg::Pos(pos) => Args::single(pos),
PosOrKwArg::Kw(kw) => Args::new(vec![], None, vec![kw], None, vec![]),
};
#[allow(clippy::while_let_loop)]
loop {
@ -2502,11 +2501,7 @@ impl Parser {
mid_expr.ln_begin().unwrap(),
mid_expr.col_begin().unwrap(),
);
let call = Call::new(
str_func,
None,
Args::pos_only(vec![PosArg::new(mid_expr)], None),
);
let call = Call::new(str_func, None, Args::single(PosArg::new(mid_expr)));
let op = Token::new(
Plus,
"+",

View file

@ -16,13 +16,13 @@ impl Parser {
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, ..) = arr.elems.deconstruct();
let (elems, .., commas) = arr.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::new(const_elems, None, vec![], None);
let elems = ConstArgs::pos_only(const_elems, None, commas);
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
Ok(ConstExpr::Array(const_arr))
}
@ -34,13 +34,13 @@ impl Parser {
},
Expr::Set(set) => match set {
Set::Normal(set) => {
let (elems, ..) = set.elems.deconstruct();
let (elems, .., commas) = set.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::new(const_elems, None, vec![], None);
let elems = ConstArgs::pos_only(const_elems, None, commas);
let const_set = ConstSet::new(set.l_brace, set.r_brace, elems);
Ok(ConstExpr::Set(const_set))
}
@ -69,13 +69,13 @@ impl Parser {
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let (elems, _, _, paren) = tup.elems.deconstruct();
let (elems, _, _, paren, commas) = tup.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::pos_only(const_elems, paren);
let elems = ConstArgs::pos_only(const_elems, paren, commas);
let const_tup = ConstTuple::new(elems);
Ok(ConstExpr::Tuple(const_tup))
}
@ -100,13 +100,13 @@ impl Parser {
"complex const function call",
));
};
let (pos_args, _, _, paren) = call.args.deconstruct();
let (pos_args, _, _, paren, commas) = call.args.deconstruct();
let mut const_pos_args = vec![];
for elem in pos_args.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
const_pos_args.push(ConstPosArg::new(const_expr));
}
let args = ConstArgs::pos_only(const_pos_args, paren);
let args = ConstArgs::pos_only(const_pos_args, paren, commas);
Ok(ConstExpr::App(ConstApp::new(acc, args)))
}
Expr::Def(def) => Self::validate_const_def(def).map(ConstExpr::Def),
@ -194,7 +194,7 @@ impl Parser {
fn call_to_predecl_type_spec(call: Call) -> Result<PreDeclTypeSpec, ParseError> {
match *call.obj {
Expr::Accessor(Accessor::Ident(ident)) => {
let (_pos_args, _var_args, _kw_args, paren) = call.args.deconstruct();
let (_pos_args, _var_args, _kw_args, paren, commas) = call.args.deconstruct();
let mut pos_args = vec![];
for arg in _pos_args.into_iter() {
let const_expr = Self::validate_const_expr(arg.expr)?;
@ -213,7 +213,7 @@ impl Parser {
}
Ok(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
ident,
ConstArgs::new(pos_args, var_args, kw_args, paren),
ConstArgs::new(pos_args, var_args, kw_args, paren, commas),
)))
}
_ => todo!(),
@ -309,12 +309,12 @@ impl Parser {
match set {
Set::Normal(set) => {
let mut elem_ts = vec![];
let (elems, .., paren) = set.elems.deconstruct();
let (elems, .., paren, commas) = set.elems.deconstruct();
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
elem_ts.push(ConstPosArg::new(const_expr));
}
Ok(TypeSpec::Enum(ConstArgs::pos_only(elem_ts, paren)))
Ok(TypeSpec::Enum(ConstArgs::pos_only(elem_ts, paren, commas)))
}
Set::WithLength(set) => {
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
@ -375,7 +375,7 @@ impl Parser {
match tuple {
Tuple::Normal(tup) => {
let mut tup_spec = vec![];
let (elems, .., parens) = tup.elems.deconstruct();
let (elems, .., parens, _commas) = tup.elems.deconstruct();
for elem in elems.into_iter() {
let value = Self::expr_to_type_spec(elem.expr)?;
tup_spec.push(value);