diff --git a/compiler/src/diagnostics.rs b/compiler/src/diagnostics.rs index 61f7a2c..3515eb1 100644 --- a/compiler/src/diagnostics.rs +++ b/compiler/src/diagnostics.rs @@ -29,6 +29,8 @@ pub enum Code { InvalidCast = 0x0207, CannotDereference = 0x0209, CannotInferType = 0x020A, + InvalidOperation = 0x020B, + InvalidParameterCount = 0x020C, UninitializedField = 0x0300, diff --git a/compiler/src/events.rs b/compiler/src/events.rs index 502e7b8..579cb58 100644 --- a/compiler/src/events.rs +++ b/compiler/src/events.rs @@ -1,15 +1,15 @@ -use crate::{diagnostics::Diagnostic, metadata::CodePosition}; +use crate::{diagnostics::Diagnostic, metadata::CodePath}; use leaf_assembly::values::AnyValue; #[derive(Debug, Clone)] pub enum Event<'l> { Symbol { value: AnyValue<'l>, - position: CodePosition, + position: CodePath, }, Definition { value: AnyValue<'l>, - position: CodePosition, + position: CodePath, }, Diagnostic(Diagnostic), } diff --git a/compiler/src/metadata.rs b/compiler/src/metadata.rs index 373f4d1..439ba53 100644 --- a/compiler/src/metadata.rs +++ b/compiler/src/metadata.rs @@ -32,3 +32,15 @@ impl CodePosition { }) } } + +#[derive(Debug, Clone)] +pub struct CodePath { + pub file: Arc, + pub path: Arc<[u32]>, +} + +impl CodePath { + pub fn new(file: Arc, path: Arc<[u32]>) -> Self { + Self { file, path } + } +} diff --git a/compiler/src/scope.rs b/compiler/src/scope.rs index 17e262a..1f855fc 100755 --- a/compiler/src/scope.rs +++ b/compiler/src/scope.rs @@ -1,4 +1,9 @@ -use crate::{CompilationContext, FuncQueue, diagnostics::*, events::Event, metadata::CodePosition}; +use crate::{ + CompilationContext, FuncQueue, + diagnostics::*, + events::Event, + metadata::{CodePath, CodePosition}, +}; use arcstr::{Substr, literal_substr}; use leaf_assembly::{ assembly::Assembly, @@ -16,6 +21,7 @@ use leaf_assembly::{ use leaf_parser::{ SourceCode, ast::{self, *}, + no_path, }; use std::{ borrow::Cow, @@ -80,8 +86,8 @@ impl<'l> Scope<'l> { pub fn declare_constants(&mut self, decl: &[AstNode]) { for val in decl { - for range in val.names.as_slice() { - let name = self.get_text_arc(range); + for name in val.names.as_slice() { + let name = self.get_text_arc(&name.range); self.values.insert( name, Variable { @@ -109,7 +115,7 @@ impl<'l> Scope<'l> { )?; match &*val.names { NamePattern::Single(ident) => { - let name = self.get_text(ident).to_string(); + let name = self.get_text(&ident.range).to_string(); self.values .get_mut(&*name) @@ -120,7 +126,7 @@ impl<'l> Scope<'l> { self.ctx.emit_event(Event::Definition { value: expr, - position: CodePosition::new(self.source.clone(), ident.clone()), + position: CodePath::new(self.source.clone(), ident.path.clone()), }); } NamePattern::Tuple(_) => todo!(), @@ -161,6 +167,7 @@ impl<'l> Scope<'l> { &AstNode { range: block.range.clone(), node: Expr::Block(block.clone()), + path: no_path(), }, &func.ty.ret_t, )?; @@ -179,14 +186,14 @@ impl<'l> Scope<'l> { ctx: &mut ExpressionContext<'l, '_>, ) -> Result, Diagnostic> { match &**expr { - Expr::Ident(range) => { - let name = self.get_text(range); + Expr::Ident => { + let name = self.get_text(&expr.range); match self.values.get(&*name) { None => Err(Diagnostic { kind: Kind::Error, code: Code::SymbolNotFound, message: format!("Symbol `{name}` does not exist in the current scope."), - position: CodePosition::new(self.source.clone(), range.clone()), + position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: None, }), Some(Variable { value, .. }) => match value.get() { @@ -194,13 +201,13 @@ impl<'l> Scope<'l> { kind: Kind::Error, code: Code::UninitializedSymbol, message: format!("Symbol `{name}` is not initialized at this time."), - position: CodePosition::new(self.source.clone(), range.clone()), + position: CodePosition::new(self.source.clone(), expr.range.clone()), cause: None, }), Some(value) => { self.ctx.emit_event(Event::Symbol { value: *value, - position: CodePosition::new(self.source.clone(), range.clone()), + position: CodePath::new(self.source.clone(), expr.path.clone()), }); Ok(*value) } @@ -241,7 +248,7 @@ impl<'l> Scope<'l> { }) }}; } - let ty = n.ty.as_ref().map(|v| self.get_text(v)); + let ty = n.ty.as_ref().map(|v| self.get_text(&v.range)); let value = match ty.as_ref().map(|ty| &**ty) { None if ctx.type_hint == Some(Type::I8) => parse_number!(i8, I8), None if ctx.type_hint == Some(Type::I16) => parse_number!(i16, I16), @@ -273,13 +280,16 @@ impl<'l> Scope<'l> { kind: Kind::Error, code: Code::InvalidIntegerType, message: format!("`{ty}` is not a valid integer type."), - position: CodePosition::new(self.source.clone(), n.ty.clone().unwrap()), + position: CodePosition::new( + self.source.clone(), + n.ty.clone().unwrap().range, + ), cause: None, }), }?; self.ctx.emit_event(Event::Symbol { value: value, - position: CodePosition::new(self.source.clone(), n.number.clone()), + position: CodePath::new(self.source.clone(), expr.path.clone()), }); Ok(value) } @@ -290,7 +300,7 @@ impl<'l> Scope<'l> { field, } => { let value = self.compile_expression(value_expr, ctx)?; - let name = self.get_text(field); + let name = self.get_text(&field.range); if let Some(value) = value.get_associated_value(&*name) { return Ok(value); } @@ -341,7 +351,7 @@ impl<'l> Scope<'l> { if let Some(value) = value { self.ctx.emit_event(Event::Symbol { value: value, - position: CodePosition::new(self.source.clone(), field.clone()), + position: CodePath::new(self.source.clone(), field.path.clone()), }); return Ok(value); } @@ -350,7 +360,7 @@ impl<'l> Scope<'l> { kind: Kind::Error, code: Code::FieldNotFound, message: format!("Value does not contain field `{name}`."), - position: CodePosition::new(self.source.clone(), field.clone()), + position: CodePosition::new(self.source.clone(), field.range.clone()), cause: None, }); } @@ -528,17 +538,20 @@ impl<'l> Scope<'l> { _ => todo!("{src_ty} as {dst_ty}"), } } - (a, b, _) => todo!( - "{a} {op:?} {b} | {lhs:?} {op:?} {rhs:?}", - op = operator.node, - ), + (a, b, _) => Err(Diagnostic { + kind: Kind::Error, + code: Code::InvalidOperation, + message: format!("Cannot perform operation between types `{a}` and `{b}`."), + position: CodePosition::new(self.source.clone(), expr.range.clone()), + cause: None, + }), } } Expr::If(expr) => self.compile_if(expr, ctx), Expr::While(expr) => { - let While { cond, block, .. } = &**expr; + let While { cond, block, .. } = &expr.node; let mut builder = ctx.builder.as_mut().unwrap(); let cond_block = builder.create_block(); @@ -577,14 +590,32 @@ impl<'l> Scope<'l> { }); } }; + if args_exprs.len() != func.ty.par_t.len() { + return Err(Diagnostic { + kind: Kind::Error, + code: Code::InvalidParameterCount, + message: format!( + "Expected {} parameters, found {}.", + func.ty.par_t.len(), + args_exprs.len() + ), + position: CodePosition::new(self.source.clone(), expr.range.clone()), + cause: None, + }); + } let mut arg_ty = func.ty.par_t.iter().cloned(); let mut args = Vec::with_capacity(args_exprs.len()); for expr in args_exprs { + let expected = arg_ty.next(); let mut arg = - self.compile_expression(expr, &mut ctx.with_type_hit(arg_ty.next()))?; + self.compile_expression(expr, &mut ctx.with_type_hit(expected))?; + if arg.is_lvalue() { arg = ctx.builder.as_mut().unwrap().load(arg).unwrap(); } + + self.assert_ty_eq(&arg, expr, expected.as_ref().unwrap())?; + args.push(arg); } let builder = ctx.builder.as_mut().unwrap(); @@ -627,7 +658,7 @@ impl<'l> Scope<'l> { }, Expr::Struct { fields, .. } => { let name = match &ctx.decl_names { - Some(NamePattern::Single(func_name)) => &*self.get_text(func_name), + Some(NamePattern::Single(func_name)) => &*self.get_text(&func_name.range), _ => "", }; let struct_ty = self.assembly.create_struct(name); @@ -651,10 +682,11 @@ impl<'l> Scope<'l> { public, mutable, }, + .. } in fields { let ty = scope.compile_expression(ty_expr, &mut expr_ctx)?; - let name = ctx.intern_str(&self.get_text(name)); + let name = ctx.intern_str(&self.get_text(&name.range)); field_map.insert( name, Field { @@ -852,7 +884,7 @@ impl<'l> Scope<'l> { } in fields.values() { let Some(name_value_pair) = ctor_values.iter().find_map(|v| { - let name = self.get_text(&v.name); + let name = self.get_text(&v.name.range); match name == *fld_name { true => Some(&v.node), false => None, @@ -910,6 +942,7 @@ impl<'l> Scope<'l> { let ast_as_expr = AstNode { range: ast.range.clone(), node: Expr::Func(ast.clone()), + path: no_path(), }; let ret_ty = self.assert_ty(ret_ty, ast.ret.as_ref().unwrap_or(&ast_as_expr))?; let mut par_ty = Vec::with_capacity(ast.args.len()); @@ -921,7 +954,7 @@ impl<'l> Scope<'l> { let fn_ty = ret_ty.make_fn(par_ty); let name = match &ctx.decl_names { - Some(NamePattern::Single(func_name)) => &*self.get_text(func_name), + Some(NamePattern::Single(func_name)) => &*self.get_text(&func_name.range), _ => "", }; let func = self.assembly.create_function(fn_ty, name); @@ -931,7 +964,7 @@ impl<'l> Scope<'l> { let mut scope = self.clone(); for (i, arg) in ast.args.iter().enumerate() { - let name = self.get_text_arc(&arg.name); + let name = self.get_text_arc(&arg.name.range); scope.insert(name, AnyValue::Parameter(i, func)); } @@ -965,7 +998,7 @@ impl<'l> Scope<'l> { } match names { NamePattern::Single(ident) => { - let name = self.get_text_arc(ident); + let name = self.get_text_arc(&ident.range); self.values.insert( name, Variable { @@ -975,7 +1008,7 @@ impl<'l> Scope<'l> { self.ctx.emit_event(Event::Definition { value: value, - position: CodePosition::new(self.source.clone(), ident.clone()), + position: CodePath::new(self.source.clone(), ident.path.clone()), }); } NamePattern::Tuple(_) => todo!(), diff --git a/lsp/src/main.rs b/lsp/src/main.rs index b264106..21de447 100644 --- a/lsp/src/main.rs +++ b/lsp/src/main.rs @@ -1,4 +1,4 @@ -use crate::parsing::semantic_tokens; +use crate::syntax_tokens::semantic_tokens; use crate::utils::UriUtils; use crate::workspace::{Workspace, start_workspace_thread}; use std::sync::Arc; @@ -8,7 +8,7 @@ use tower_lsp_server::ls_types::request::{GotoDeclarationParams, GotoDeclaration use tower_lsp_server::{Client, LspService, Server}; use tower_lsp_server::{LanguageServer, ls_types::*}; -mod parsing; +mod syntax_tokens; mod utils; mod workspace; diff --git a/lsp/src/parsing.rs b/lsp/src/syntax_tokens.rs similarity index 57% rename from lsp/src/parsing.rs rename to lsp/src/syntax_tokens.rs index d0755f9..7afd328 100644 --- a/lsp/src/parsing.rs +++ b/lsp/src/syntax_tokens.rs @@ -1,7 +1,11 @@ use crate::utils::{correct_semantic_token_deltas, make_diagnostics}; +use leaf_assembly::{ + functions::ir::{Instruction, InstructionVariant}, + values::{AnyConst, AnyValue}, +}; use leaf_compiler::metadata::CodePosition; use leaf_parser::{SourceCode, Text, ast::*}; -use std::{sync::Arc, time::Instant}; +use std::{collections::HashMap, sync::Arc, time::Instant, u32}; use tower_lsp_server::ls_types::{Diagnostic, SemanticToken, SemanticTokens, SemanticTokensResult}; pub mod semantic_tokens { @@ -27,17 +31,29 @@ pub mod semantic_tokens { pub const OPERATOR: u32 = 7; } -pub struct DocumentParsingResult { +pub struct DocumentSyntax { pub tokens: SemanticTokensResult, pub diagnostics: Vec, } -pub fn parse_document(code: &Arc) -> DocumentParsingResult { +impl Default for DocumentSyntax { + fn default() -> Self { + Self { + tokens: SemanticTokensResult::Tokens(SemanticTokens::default()), + diagnostics: Default::default(), + } + } +} + +pub fn generate_syntax_tokens( + code: &Arc, + symbols: &HashMap, [u8; size_of::()]>, +) -> DocumentSyntax { let now = Instant::now(); let ast = match code.ast() { Ok(d) => d, Err(err) => { - return DocumentParsingResult { + return DocumentSyntax { tokens: SemanticTokensResult::Tokens(SemanticTokens::default()), diagnostics: make_diagnostics( &leaf_compiler::diagnostics::Diagnostic::parsing_err(code.clone(), err.clone()), @@ -48,7 +64,7 @@ pub fn parse_document(code: &Arc) -> DocumentParsingResult { let mut tokens = SemanticTokens::default(); for decl in &ast.decls { - decl.push_semantic_tokens(code, &mut tokens, None); + decl.push_semantic_tokens(code, &mut tokens, None, symbols); } correct_semantic_token_deltas(&mut tokens); @@ -64,7 +80,7 @@ pub fn parse_document(code: &Arc) -> DocumentParsingResult { size as f32 / 1000.0, now.elapsed() ); - DocumentParsingResult { + DocumentSyntax { tokens: SemanticTokensResult::Tokens(tokens), diagnostics: vec![], } @@ -90,6 +106,7 @@ trait PushSemanticTokens { file: &Arc, tokens: &mut SemanticTokens, hint: Option, + symbols: &HashMap, [u8; size_of::()]>, ); } @@ -99,24 +116,44 @@ impl PushSemanticTokens for AstNode { file: &Arc, tokens: &mut SemanticTokens, hint: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { - match self.names.as_slice() { - [ident] => { - push_token!( - file, - tokens, - ident, - match &self.value.node { + if let [ident] = self.names.as_slice() { + push_token!( + file, + tokens, + ident.range, + match symbols.get(&ident.path) { + Some(symbol) => get_semantic_token(*symbol), + None => match &self.value.node { Expr::Func(_) => semantic_tokens::FUNCTION, - Expr::Ptr { .. } => semantic_tokens::TYPE, Expr::Struct { .. } => semantic_tokens::TYPE, _ => semantic_tokens::VARIABLE, - } - ); - } - _ => {} + }, + } + ) } - self.value.push_semantic_tokens(file, tokens, hint); + self.value.push_semantic_tokens(file, tokens, hint, symbols); + } +} + +impl PushSemanticTokens for AstNode<()> { + fn push_semantic_tokens( + &self, + file: &Arc, + tokens: &mut SemanticTokens, + hint: Option, + symbols: &HashMap, [u8; size_of::()]>, + ) { + push_token!( + file, + tokens, + self.range, + match symbols.get(&self.path) { + Some(symbol) => get_semantic_token(*symbol), + None => hint.unwrap_or(semantic_tokens::VARIABLE), + } + ) } } @@ -126,21 +163,25 @@ impl PushSemanticTokens for AstNode { file: &Arc, tokens: &mut SemanticTokens, hint: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { match &self.node { - Expr::Ident(range) => { + Expr::Ident => { push_token!( file, tokens, - range, - hint.unwrap_or(semantic_tokens::VARIABLE) + self.range, + match symbols.get(&self.path) { + Some(v) => get_semantic_token(*v), + None => hint.unwrap_or(semantic_tokens::VARIABLE), + } ); } Expr::Number(_) => { push_token!(file, tokens, self.range, semantic_tokens::NUMBER); } - Expr::If(expr) => expr.push_semantic_tokens(file, tokens, None), - Expr::While(expr) => expr.push_semantic_tokens(file, tokens, None), + Expr::If(expr) => expr.push_semantic_tokens(file, tokens, None, symbols), + Expr::While(expr) => expr.push_semantic_tokens(file, tokens, None, symbols), Expr::Func(func) => { let Function { fn_tok, @@ -155,14 +196,14 @@ impl PushSemanticTokens for AstNode { .. } in args { - push_token!(file, tokens, name, semantic_tokens::PARAMETER); - value.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE)); + push_token!(file, tokens, name.range, semantic_tokens::PARAMETER); + value.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } if let Some(ret) = ret { - push_token!(file, tokens, ret.range, semantic_tokens::TYPE); + ret.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } if let Some(block) = block { - block.push_semantic_tokens(file, tokens, hint); + block.push_semantic_tokens(file, tokens, None, symbols); } } Expr::VarDecl(expr) => { @@ -170,34 +211,34 @@ impl PushSemanticTokens for AstNode { names, r#type, value, - } = &**expr; - for range in names.as_slice() { - push_token!(file, tokens, range, semantic_tokens::VARIABLE); + } = &expr.node; + for node in names.as_slice() { + push_token!(file, tokens, node.range, semantic_tokens::VARIABLE); } if let Some(ty) = r#type { - ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE)); + ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } - value.push_semantic_tokens(file, tokens, hint); + value.push_semantic_tokens(file, tokens, None, symbols); } Expr::ConstDecl(expr) => { let ConstDecl { names, r#type, value, - } = &**expr; - for range in names.as_slice() { - push_token!(file, tokens, range, semantic_tokens::VARIABLE); + } = &expr.node; + for node in names.as_slice() { + push_token!(file, tokens, node.range, semantic_tokens::VARIABLE); } if let Some(ty) = r#type { - ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE)); + ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } - value.push_semantic_tokens(file, tokens, hint); + value.push_semantic_tokens(file, tokens, None, symbols); } Expr::Ptr { mutable, base, .. } => { if let Some(mutable) = mutable { push_token!(file, tokens, mutable, semantic_tokens::KEYWORD); } - base.push_semantic_tokens(file, tokens, hint); + base.push_semantic_tokens(file, tokens, hint, symbols); } Expr::Struct { fields, struct_tok } => { push_token!(file, tokens, struct_tok, semantic_tokens::KEYWORD); @@ -217,8 +258,8 @@ impl PushSemanticTokens for AstNode { if let Some(mutable) = mutable { push_token!(file, tokens, mutable, semantic_tokens::KEYWORD); } - push_token!(file, tokens, name, semantic_tokens::PROPERTY); - ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE)); + push_token!(file, tokens, name.range, semantic_tokens::PROPERTY); + ty.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } } Expr::StructCtor { ty, values } => { @@ -226,11 +267,11 @@ impl PushSemanticTokens for AstNode { push_token!(file, tokens, ty.range, semantic_tokens::TYPE); } for value in values { - value.push_semantic_tokens(file, tokens, None); + value.push_semantic_tokens(file, tokens, None, symbols); } } Expr::Deref { value, operator } => { - value.push_semantic_tokens(file, tokens, None); + value.push_semantic_tokens(file, tokens, None, symbols); push_token!(file, tokens, operator, semantic_tokens::OPERATOR); } Expr::Binary { @@ -238,31 +279,31 @@ impl PushSemanticTokens for AstNode { operator: AstNode { node: BinaryOperator::Cast, range, + .. }, rhs, } => { - lhs.push_semantic_tokens(file, tokens, None); + lhs.push_semantic_tokens(file, tokens, None, symbols); push_token!(file, tokens, range, semantic_tokens::KEYWORD); - rhs.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE)); + rhs.push_semantic_tokens(file, tokens, Some(semantic_tokens::TYPE), symbols); } Expr::Binary { lhs, rhs, operator: AstNode { range, .. }, } => { - lhs.push_semantic_tokens(file, tokens, None); - rhs.push_semantic_tokens(file, tokens, None); + lhs.push_semantic_tokens(file, tokens, None, symbols); + rhs.push_semantic_tokens(file, tokens, None, symbols); push_token!(file, tokens, range, semantic_tokens::OPERATOR); } Expr::Access { value, field, .. } => { - push_token!(file, tokens, value.range, semantic_tokens::VARIABLE); - push_token!(file, tokens, field, semantic_tokens::PROPERTY); - value.push_semantic_tokens(file, tokens, None); + value.push_semantic_tokens(file, tokens, Some(semantic_tokens::VARIABLE), symbols); + field.push_semantic_tokens(file, tokens, Some(semantic_tokens::PROPERTY), symbols); } Expr::Call { func, args } => { - push_token!(file, tokens, func.range, semantic_tokens::FUNCTION); + func.push_semantic_tokens(file, tokens, Some(semantic_tokens::FUNCTION), symbols); for arg in args.iter() { - arg.push_semantic_tokens(file, tokens, None); + arg.push_semantic_tokens(file, tokens, None, symbols); } } _ => {} @@ -276,9 +317,10 @@ impl PushSemanticTokens for Block { file: &Arc, tokens: &mut SemanticTokens, _: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { for expr in &self.0 { - expr.push_semantic_tokens(file, tokens, None); + expr.push_semantic_tokens(file, tokens, None, symbols); } } } @@ -289,19 +331,20 @@ impl PushSemanticTokens for If { file: &Arc, tokens: &mut SemanticTokens, _: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { push_token!(file, tokens, self.if_tok, semantic_tokens::KEYWORD); - self.cond.push_semantic_tokens(file, tokens, None); - self.block.push_semantic_tokens(file, tokens, None); + self.cond.push_semantic_tokens(file, tokens, None, symbols); + self.block.push_semantic_tokens(file, tokens, None, symbols); if let Some(expr) = &self.else_ { match &**expr { Else::If { else_tok, expr } => { push_token!(file, tokens, else_tok, semantic_tokens::KEYWORD); - expr.push_semantic_tokens(file, tokens, None); + expr.push_semantic_tokens(file, tokens, None, symbols); } Else::Block { else_tok, expr } => { push_token!(file, tokens, else_tok, semantic_tokens::KEYWORD); - expr.push_semantic_tokens(file, tokens, None); + expr.push_semantic_tokens(file, tokens, None, symbols); } } } @@ -314,10 +357,11 @@ impl PushSemanticTokens for While { file: &Arc, tokens: &mut SemanticTokens, _: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { push_token!(file, tokens, self.while_tok, semantic_tokens::KEYWORD); - self.cond.push_semantic_tokens(file, tokens, None); - self.block.push_semantic_tokens(file, tokens, None); + self.cond.push_semantic_tokens(file, tokens, None, symbols); + self.block.push_semantic_tokens(file, tokens, None, symbols); } } @@ -327,8 +371,31 @@ impl PushSemanticTokens for NameValuePair { file: &Arc, tokens: &mut SemanticTokens, _: Option, + symbols: &HashMap, [u8; size_of::()]>, ) { - push_token!(file, tokens, self.name, semantic_tokens::PROPERTY); - self.value.push_semantic_tokens(file, tokens, None); + push_token!(file, tokens, self.name.range, semantic_tokens::PROPERTY); + self.value.push_semantic_tokens(file, tokens, None, symbols); + } +} + +fn get_semantic_token(value: [u8; size_of::()]) -> u32 { + let value: AnyValue = unsafe { std::mem::transmute(value) }; + match value { + AnyValue::Parameter(_, _) => semantic_tokens::PARAMETER, + AnyValue::Constant(AnyConst::Type(_)) => semantic_tokens::TYPE, + AnyValue::Constant(AnyConst::Function(_)) => semantic_tokens::FUNCTION, + AnyValue::Instruction(Instruction { + variant: + InstructionVariant::GetElementPtr(_, _) | InstructionVariant::GetElementVal(_, _), + .. + }) => semantic_tokens::PROPERTY, + AnyValue::Instruction(Instruction { + variant: InstructionVariant::StackAlloc(_) | InstructionVariant::GCAlloc(_), + .. + }) => semantic_tokens::VARIABLE, + _ => { + eprintln!("unknown value case {value:?}"); + u32::MAX + } } } diff --git a/lsp/src/workspace.rs b/lsp/src/workspace.rs index 0554196..7a44ca4 100644 --- a/lsp/src/workspace.rs +++ b/lsp/src/workspace.rs @@ -1,40 +1,33 @@ use leaf_allocators::SyncArenaAllocator; -use leaf_assembly::{ - assembly::{AssemblyIdentifier, Version}, - types::{Type, derivations::PtrT}, - values::{AnyConst, AnyValue, Value}, -}; -use leaf_compiler::{CompilationContext, events::Event, metadata::CodePosition}; +use leaf_assembly::assembly::{AssemblyIdentifier, Version}; +use leaf_compiler::{CompilationContext, events::Event}; use leaf_parser::{ArcStr, SourceCode, Text}; -use rangemap::RangeMap; use ropey::Rope; use rust_search::SearchBuilder; use std::{ borrow::Cow, + cell::RefCell, collections::HashMap, - fmt::Write, - ops::Range, path::PathBuf, - str::FromStr, - sync::{Arc, OnceLock}, + sync::{Arc, Mutex, OnceLock}, + time::Instant, }; use tokio::sync::{ - Mutex, Notify, RwLock, + Notify, mpsc::{Sender, channel}, }; use tower_lsp_server::{ Client, ls_types::{ - Diagnostic, DidChangeTextDocumentParams, Hover, HoverContents, HoverParams, Location, - MarkedString, Position, SemanticToken, SemanticTokens, SemanticTokensParams, - SemanticTokensResult, TextDocumentPositionParams, Uri, + DidChangeTextDocumentParams, Hover, HoverParams, Position, SemanticTokensParams, + SemanticTokensResult, Uri, request::{GotoDeclarationParams, GotoDeclarationResponse}, }, }; use crate::{ - parsing::{DocumentParsingResult, parse_document}, - utils::{CodePositionUtils, UriUtils, correct_semantic_token_deltas, make_diagnostics}, + syntax_tokens::{DocumentSyntax, generate_syntax_tokens}, + utils::{UriUtils, make_diagnostics}, }; pub struct Workspace { @@ -116,115 +109,193 @@ enum Request { ), } +#[derive(Default)] +struct State { + file_text: Mutex>, + file_code: Mutex, i32)>>, + file_docs: Mutex>>, + compilation_state: Arc>, +} + +impl State { + pub fn with_file_text(&self, uri: Uri, action: impl FnOnce(&mut (Rope, i32)) -> T) -> T { + let mut file_text = self.file_text.lock().unwrap(); + action(file_text.entry(uri).or_insert_with_key(|key| { + let path = key.strip_header(); + (Rope::from_str(&std::fs::read_to_string(path).unwrap()), 0) + })) + } + + pub fn with_file_code( + &self, + uri: Uri, + action: impl FnOnce(&mut (Arc, i32)) -> T, + ) -> T { + self.with_file_text(uri.clone(), |(text, version)| { + let mut file_code = self.file_code.lock().unwrap(); + let entry = match file_code.get_mut(&uri) { + None => file_code.entry(uri).or_insert_with_key(|uri| { + ( + SourceCode { + file: uri.strip_header().into(), + text: Text::ArcStr(ArcStr::from(text.to_string()), OnceLock::new()), + ast: OnceLock::new(), + } + .into(), + *version, + ) + }), + Some(entry) => { + if entry.1 != *version { + entry.0 = SourceCode { + file: uri.strip_header().into(), + text: Text::ArcStr(ArcStr::from(text.to_string()), OnceLock::new()), + ast: OnceLock::new(), + } + .into(); + entry.1 = *version; + self.file_docs.lock().unwrap().remove(&uri); + } + entry + } + }; + action(entry) + }) + } +} + +#[derive(Default)] +enum CompilationState { + #[default] + None, + Compiling, + Compiled(Instant), +} + pub fn start_workspace_thread(url: Uri, client: Client) -> Result, String> { let base = url.strip_header().to_string(); + let path = PathBuf::from(&base); let (sender, mut receiver) = channel(1); let _handle = tokio::task::spawn(async move { let mut alloc = SyncArenaAllocator::default(); - let mut file_text = HashMap::::new(); - let mut files = HashMap::, i32)>::new(); - let mut parsed = HashMap::::new(); - - macro_rules! get_file_text { - ($uri:expr, $version:expr) => { - file_text.entry($uri).or_insert_with_key(|key| { - let path = key.strip_header(); - ( - Rope::from_str(&std::fs::read_to_string(path).unwrap()), - $version, - ) - }) - }; - } + let state = Arc::new(State::default()); 'global: loop { alloc.reset(); + let symbols = Arc::new(Mutex::new(HashMap::new())); + + let mut files = vec![]; + for file in SearchBuilder::default().location(&path).ext("leaf").build() { + state.with_file_code(Uri::from_file_path(file).unwrap(), |(code, _)| { + files.push(code.clone()); + }); + } + + let now = Instant::now(); + let mut context = CompilationContext::new(&alloc); + { + let state = state.clone(); + let symbols = symbols.clone(); + context.add_event_callback(move |e| unsafe { + match e { + Event::Symbol { value, position } => { + let mut symbols = symbols.lock().unwrap(); + symbols.insert(position.path.clone(), std::mem::transmute(*value)); + } + Event::Definition { value, position } => { + let mut symbols = symbols.lock().unwrap(); + symbols.insert(position.path.clone(), std::mem::transmute(*value)); + } + Event::Diagnostic(diag) => { + let uri = Uri::from_file_path(&diag.position.file.file).unwrap(); + let mut file_docs = state.file_docs.lock().unwrap(); + if let Some(docs) = file_docs.get_mut(&uri) { + let docs = Arc::get_mut(docs).unwrap(); + docs.diagnostics.extend(make_diagnostics(diag)); + } + } + } + }); + } + + if let Err(err) = context.extend( + AssemblyIdentifier { + version: Version::default(), + name: Cow::Borrowed("Leaf lsp tmp"), + }, + &files, + ) { + let uri = Uri::from_file_path(&err.position.file.file).unwrap(); + let diagnostics = { + let mut file_docs = state.file_docs.lock().unwrap(); + if let Some(docs) = file_docs.get_mut(&uri) { + let docs = Arc::get_mut(docs).unwrap(); + docs.diagnostics.extend(make_diagnostics(&err)); + docs.diagnostics.clone() + } else { + vec![] + } + }; + client.publish_diagnostics(uri, diagnostics, None).await; + eprintln!("Compilation failed in {:?}", now.elapsed()); + } else { + client.semantic_tokens_refresh().await.unwrap(); + eprintln!("Compilation succeeded in {:?}", now.elapsed()); + } + while let Some(event) = receiver.recv().await { match event { - Request::Reload => continue 'global, - Request::Hover(params, result) => { + Request::Reload => { + continue 'global; + } + Request::Hover(_params, result) => { result.1.notify_one(); } - Request::GoToDeclaration(params, result) => { + Request::GoToDeclaration(_params, result) => { result.1.notify_one(); } Request::FileChanged(params) => { - let (file, version) = get_file_text!( + state.with_file_text( params.text_document.uri.clone(), - params.text_document.version + |(file, version)| { + eprintln!("File {:?} changed", params.text_document.uri.as_str()); + for change in params.content_changes { + let Some(range) = change.range else { + *file = Rope::from_str(&change.text); + continue; + }; + + fn pos_to_char_index( + rope: &ropey::Rope, + pos: Position, + ) -> usize { + let line_start = rope.line_to_char(pos.line as usize); + line_start + pos.character as usize + } + let start = pos_to_char_index(file, range.start); + let end = pos_to_char_index(file, range.end); + + file.remove(start..end); + file.insert(start, &change.text); + } + *version = params.text_document.version; + }, ); - eprintln!("File {:?} changed", params.text_document.uri.as_str()); - for change in params.content_changes { - let Some(range) = change.range else { - *file = Rope::from_str(&change.text); - continue; - }; - - fn pos_to_char_index(rope: &ropey::Rope, pos: Position) -> usize { - let line_start = rope.line_to_char(pos.line as usize); - line_start + pos.character as usize - } - let start = pos_to_char_index(file, range.start); - let end = pos_to_char_index(file, range.end); - - file.remove(start..end); - file.insert(start, &change.text); - } - *version = params.text_document.version; client.semantic_tokens_refresh().await.unwrap(); } Request::SemanticTokens(params, result) => { - eprintln!( - "Sending semantic tokens for file {:?}", - params.text_document.uri.as_str() - ); - let (file, version) = get_file_text!(params.text_document.uri.clone(), 0); - let source = match files.get_mut(¶ms.text_document.uri) { - None => { - &files + let parsed = + state.with_file_code(params.text_document.uri.clone(), |(code, _)| { + let mut file_docs = state.file_docs.lock().unwrap(); + file_docs .entry(params.text_document.uri.clone()) - .or_insert_with_key(|uri| { - ( - SourceCode { - file: uri.strip_header().into(), - text: Text::ArcStr( - ArcStr::from(file.to_string()), - OnceLock::new(), - ), - ast: OnceLock::new(), - } - .into(), - *version, - ) + .or_insert_with(|| { + let symbols = symbols.lock().unwrap(); + Arc::new(generate_syntax_tokens(code, &symbols)) }) - .0 - } - Some((source, v)) => { - if *v != *version { - eprintln!( - "Updating file {:?}", - params.text_document.uri.as_str() - ); - *source = SourceCode { - file: params.text_document.uri.strip_header().into(), - text: Text::ArcStr( - ArcStr::from(file.to_string()), - OnceLock::new(), - ), - ast: OnceLock::new(), - } - .into(); - *v = *version; - parsed.remove(¶ms.text_document.uri); - } - source - } - }; - - let parsed = parsed - .entry(params.text_document.uri.clone()) - .or_insert_with(|| parse_document(source)); + .clone() + }); let _ = client .publish_diagnostics( diff --git a/parser/src/ast.rs b/parser/src/ast.rs index b9a3ea1..29bf4c5 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -22,6 +22,7 @@ pub enum BinaryOperator { #[derive(Debug, Deref, Clone)] pub struct AstNode { + pub path: Arc<[u32]>, pub range: Range, #[deref] pub node: T, @@ -30,27 +31,27 @@ pub struct AstNode { #[derive(Debug, Clone)] pub struct Number { pub number: Range, - pub ty: Option>, + pub ty: Option>, } #[derive(Debug, Clone)] pub enum Expr { Number(Number), String(Range), - Ident(Range), + Ident, Uninit(Range), - If(Box), + If(Box>), Func(Arc>), - While(Box), + While(Box>), Block(Arc>), - VarDecl(Box), - ConstDecl(Box), + VarDecl(Box>), + ConstDecl(Box>), List(Vec>), Tuple(Vec>), Access { value: Box>, operator: Range, - field: Range, + field: AstNode<()>, }, Deref { value: Box>, @@ -97,7 +98,7 @@ pub struct Import { #[derive(Debug, Clone)] pub struct Field { - pub name: Range, + pub name: AstNode<()>, pub ty: AstNode, pub public: Option>, pub mutable: Option>, @@ -105,19 +106,27 @@ pub struct Field { #[derive(Debug, Clone)] pub enum NamePattern { - Single(Range), - Tuple(Vec>), - List(Vec>), + Single(AstNode<()>), + Tuple(Vec>), + List(Vec>), } impl NamePattern { - pub fn as_slice(&self) -> &[Range] { + pub fn as_slice(&self) -> &[AstNode<()>] { match self { NamePattern::Single(ident) => std::slice::from_ref(ident), NamePattern::Tuple(idents) => idents.as_slice(), NamePattern::List(idents) => idents.as_slice(), } } + + pub(crate) fn as_mut_slice(&mut self) -> &mut [AstNode<()>] { + match self { + NamePattern::Single(ident) => std::slice::from_mut(ident), + NamePattern::Tuple(idents) => idents.as_mut_slice(), + NamePattern::List(idents) => idents.as_mut_slice(), + } + } } #[derive(Debug, Clone)] @@ -174,13 +183,13 @@ pub struct Function { #[derive(Debug, Clone)] pub struct Parameter { - pub name: Range, + pub name: AstNode<()>, pub value: AstNode, } #[derive(Debug, Clone)] pub struct NameValuePair { - pub name: Range, + pub name: AstNode<()>, pub value: AstNode, } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 82b2453..3b573dd 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -1,9 +1,10 @@ pub use arcstr::{ArcStr, Substr}; use derive_more::Display; -pub use parser::{compilation_unit as parse, *}; +pub use parser::*; use rangemap::RangeMap; use std::{ fmt::Debug, + ops::Range, path::{Path, PathBuf}, sync::OnceLock, }; @@ -11,10 +12,11 @@ use std::{ #[cfg(feature = "rope")] pub use ropey::Rope; -use crate::ast::AstRoot; +use crate::{ast::AstRoot, path::ComputePaths}; pub mod ast; mod parser; +mod path; #[derive(Display)] pub enum Text { @@ -22,7 +24,7 @@ pub enum Text { #[display("{_0}")] Rope(Rope), #[display("{_0}")] - ArcStr(ArcStr, OnceLock>), + ArcStr(ArcStr, OnceLock)>>), } pub struct SourceCode { @@ -68,3 +70,9 @@ impl Debug for SourceCode { .finish_non_exhaustive() } } + +pub fn parse(src: &SourceCode) -> Result> { + let mut ast = compilation_unit(src)?; + ast.compute_paths(&mut vec![]); + Ok(ast) +} diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 79927b0..4065807 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -6,6 +6,9 @@ use peg::{ParseElem, ParseLiteral}; pub use peg::{error::*, str::LineCol}; use rangemap::RangeMap; use std::ops::Range; +use std::sync::Arc; +use std::sync::OnceLock; +use std::time::Instant; impl Parse for SourceCode { type PositionRepr = LineCol; @@ -42,14 +45,14 @@ impl Parse for SourceCode { let lines = lines.get_or_init(|| { let mut lines = RangeMap::new(); for (i, text) in s.split_inclusive('\n').enumerate() { - let text = s.substr_from(text); - let range = text.range(); - lines.insert(range, (i, text)); + let start = text.as_ptr() as usize - s.as_ptr() as usize; + let range = start..start + text.len(); + lines.insert(range.clone(), (i, range)); } lines }); - let (line, text) = lines.get(&p).unwrap(); - let column = p - text.range().start; + let (line, range) = lines.get(&p).unwrap(); + let column = p - range.start; Self::PositionRepr { line: *line, column, @@ -101,24 +104,29 @@ impl<'input> ParseSlice<'input> for SourceCode { } } +pub fn no_path() -> Arc<[u32]> { + static ARC: OnceLock> = OnceLock::new(); + ARC.get_or_init(Arc::default).clone() +} + peg::parser! { grammar leaf_parser() for SourceCode { // #### ATOMS #### rule number() -> AstNode = s:position!() number:$(['0'..='9']+) ty:ident()? e:position!() - { AstNode { node: Number { number, ty }, range: s..e } } + { AstNode { node: Number { number, ty }, range: s..e, path: no_path() } } / s:position!() "0x" number:$(['0'..='9'|'a'..='f'|'A'..'F']+) ty:ident()? e:position!() - { AstNode { node: Number { number, ty }, range: s..e } } + { AstNode { node: Number { number, ty }, range: s..e, path: no_path() } } / s:position!() "0b" number:$(['0'|'1']+) ty:ident()? e:position!() - { AstNode { node: Number { number, ty }, range: s..e } } + { AstNode { node: Number { number, ty }, range: s..e, path: no_path() } } - rule ident() -> Range + rule ident() -> AstNode<()> = text:$(['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) - { text } + { AstNode { range: text, node: (), path: no_path() } } - rule ident2() -> Range + rule ident2() -> AstNode<()> = text:$(['#']? ['_'|'a'..='z'|'A'..='Z']['_'|'a'..='z'|'A'..='Z'|'0'..='9']*) - { text } + { AstNode { range: text, node: (), path: no_path() } } rule string() -> Range = text:$("\"" [^'\\'|'"']* "\"") @@ -127,106 +135,106 @@ peg::parser! { // ### EXPRESSIONS #### rule bop0() -> AstNode - = op:$("as") { AstNode { range: op, node: BinaryOperator::Cast } } - / op:$("=") { AstNode { range: op, node: BinaryOperator::Assign } } + = op:$("as") { AstNode { range: op, node: BinaryOperator::Cast, path: no_path() } } + / op:$("=") { AstNode { range: op, node: BinaryOperator::Assign, path: no_path() } } rule bop1() -> AstNode - = op:$("+") { AstNode { range: op, node: BinaryOperator::Add } } - / op:$("-") { AstNode { range: op, node: BinaryOperator::Sub } } + = op:$("+") { AstNode { range: op, node: BinaryOperator::Add, path: no_path() } } + / op:$("-") { AstNode { range: op, node: BinaryOperator::Sub, path: no_path() } } rule bop2() -> AstNode - = op:$("*") { AstNode { range: op, node: BinaryOperator::Mul } } - / op:$("/") { AstNode { range: op, node: BinaryOperator::Div } } - / op:$("%") { AstNode { range: op, node: BinaryOperator::Mod } } + = op:$("*") { AstNode { range: op, node: BinaryOperator::Mul, path: no_path() } } + / op:$("/") { AstNode { range: op, node: BinaryOperator::Div, path: no_path() } } + / op:$("%") { AstNode { range: op, node: BinaryOperator::Mod, path: no_path() } } rule bop3() -> AstNode - = op:$("==") { AstNode { range: op, node: BinaryOperator::Eq } } - / op:$("!=") { AstNode { range: op, node: BinaryOperator::Ne } } - / op:$("<") { AstNode { range: op, node: BinaryOperator::Lt } } - / op:$(">") { AstNode { range: op, node: BinaryOperator::Gt } } - / op:$("<=") { AstNode { range: op, node: BinaryOperator::Le } } - / op:$(">=") { AstNode { range: op, node: BinaryOperator::Ge } } + = op:$("==") { AstNode { range: op, node: BinaryOperator::Eq, path: no_path() } } + / op:$("!=") { AstNode { range: op, node: BinaryOperator::Ne, path: no_path() } } + / op:$("<") { AstNode { range: op, node: BinaryOperator::Lt, path: no_path() } } + / op:$(">") { AstNode { range: op, node: BinaryOperator::Gt, path: no_path() } } + / op:$("<=") { AstNode { range: op, node: BinaryOperator::Le, path: no_path() } } + / op:$(">=") { AstNode { range: op, node: BinaryOperator::Ge, path: no_path() } } rule bop4() -> AstNode - = op:$("..") { AstNode { range: op, node: BinaryOperator::Range } } + = op:$("..") { AstNode { range: op, node: BinaryOperator::Range, path: no_path() } } rule expr() -> AstNode = precedence! { lhs:@ __ op:bop0() __ rhs:expr() - { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op } } } + { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op }, path: no_path() } } // -- value:@ __ op:$(".") __ field:ident2() - { AstNode { range: value.range.start..field.end, node: Expr::Access { value: value.into(), field, operator: op } } } + { AstNode { range: value.range.start..field.range.end, node: Expr::Access { value: value.into(), field, operator: op }, path: no_path() } } value:@ __ op:$(".^") - { AstNode { range: value.range.start..op.end, node: Expr::Deref { value: value.into(), operator: op } } } + { AstNode { range: value.range.start..op.end, node: Expr::Deref { value: value.into(), operator: op }, path: no_path() } } lhs:@ "(" __ args:(expr() ** list_separator()) __ e:$")" - { AstNode { range: lhs.range.start..e.end, node: Expr::Call { func: lhs.into(), args } } } + { AstNode { range: lhs.range.start..e.end, node: Expr::Call { func: lhs.into(), args }, path: no_path() } } value:@ "[" __ index:(expr() **<1,> ("," __)) __ e:$"]" - { AstNode { range: value.range.start..e.end, node: Expr::Index { value: value.into(), index } } } + { AstNode { range: value.range.start..e.end, node: Expr::Index { value: value.into(), index }, path: no_path() } } ty:@ __ "#{" __ values:name_value_pairs() __ "}" e:position!() - { AstNode { range: ty.range.start..e, node: Expr::StructCtor { ty: Some(ty.into()), values } } } + { AstNode { range: ty.range.start..e, node: Expr::StructCtor { ty: Some(ty.into()), values }, path: no_path() } } s:$"#{" __ values:name_value_pairs() __ "}" e:position!() - { AstNode { range: s.start..e, node: Expr::StructCtor { ty: None, values } } } + { AstNode { range: s.start..e, node: Expr::StructCtor { ty: None, values }, path: no_path() } } -- lhs:@ __ op:bop1() __ rhs:expr() - { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op } } } + { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op }, path: no_path() } } -- lhs:@ __ op:bop2() __ rhs:expr() - { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op } } } + { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op }, path: no_path() } } -- lhs:@ __ op:bop3() __ rhs:expr() - { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op } } } + { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op }, path: no_path() } } -- lhs:@ __ op:bop4() __ rhs:expr() - { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op } } } + { AstNode { range: lhs.range.start..rhs.range.end, node: Expr::Binary { lhs: lhs.into(), rhs: rhs.into(), operator: op }, path: no_path() } } -- - block:block() { AstNode { range: block.range.clone(), node: Expr::Block(block.into()) } } + block:block() { AstNode { range: block.range.clone(), node: Expr::Block(block.into()), path: no_path() } } - i:if_statement() { AstNode { range: i.range, node: Expr::If(i.node.into()) }} - l:while_loop() { AstNode { range: l.range, node: Expr::While(l.node.into()) }} + i:if_statement() { AstNode { range: i.range.clone(), node: Expr::If(i.into()), path: no_path() }} + l:while_loop() { AstNode { range: l.range.clone(), node: Expr::While(l.into()), path: no_path() }} - func:func() { AstNode { range: func.range.clone(), node: Expr::Func(func.into()) } } + func:func() { AstNode { range: func.range.clone(), node: Expr::Func(func.into()), path: no_path() } } var_decl:var_decl() - { AstNode { range: var_decl.range, node: Expr::VarDecl(var_decl.node.into()) } } + { AstNode { range: var_decl.range.clone(), node: Expr::VarDecl(var_decl.into()), path: no_path() } } const_decl:const_decl() - { AstNode { range: const_decl.range, node: Expr::ConstDecl(const_decl.node.into()) } } + { AstNode { range: const_decl.range.clone(), node: Expr::ConstDecl(const_decl.into()), path: no_path() } } s:$"(" __ elements:(expr() **<2,> ("," __)) __ e:$")" - { AstNode { range: s.start..e.end, node: Expr::Tuple(elements) } } + { AstNode { range: s.start..e.end, node: Expr::Tuple(elements), path: no_path() } } s:$"[" __ elements:(expr() **<2,> ("," __)) __ e:$"]" - { AstNode { range: s.start..e.end, node: Expr::List(elements) } } + { AstNode { range: s.start..e.end, node: Expr::List(elements), path: no_path() } } s:$"(" __ v:expr() __ e:$")" - { AstNode { range: s.start..e.end, node: v.node } } + { AstNode { range: s.start..e.end, node: v.node, path: no_path() } } t:$"*" __ m:$"mut"? __ v:expr() - { AstNode { range: t.start..v.range.end, node: Expr::Ptr { ptr_tok: t, mutable: m, base: v.into() } } } + { AstNode { range: t.start..v.range.end, node: Expr::Ptr { ptr_tok: t, mutable: m, base: v.into() }, path: no_path() } } v:struct_t() { v } - v:string() { AstNode { range: v.clone(), node: Expr::String(v) } } - v:number() { AstNode { range: v.range, node: Expr::Number(v.node) } } - v:ident() { AstNode { range: v.clone(), node: Expr::Ident(v) } } + v:string() { AstNode { range: v.clone(), node: Expr::String(v), path: no_path() } } + v:number() { AstNode { range: v.range, node: Expr::Number(v.node), path: no_path() } } + v:ident() { AstNode { range: v.range.clone(), node: Expr::Ident, path: no_path() } } } rule block() -> AstNode = s:$"{" __ exprs:(i:expr() statement_separator() {i})* __ e:$"}" - { AstNode { range: s.start..e.end, node: Block(exprs) } } + { AstNode { range: s.start..e.end, node: Block(exprs), path: no_path() } } rule func() -> AstNode = s:position!() t:$"fn" __ "(" __ args:parameters() __ ")" __ ret:("->" __ e:expr() {e})? __ block:block()? e:position!() - { AstNode { range: s..e, node: Function { args, ret, block: block.map(Into::into), fn_tok: t, } } } + { AstNode { range: s..e, node: Function { args, ret, block: block.map(Into::into), fn_tok: t, }, path: no_path() } } rule parameter() -> AstNode = name:ident() __ ":" __ value:expr() - { AstNode { range: name.start..value.range.end, node: Parameter { name, value } } } + { AstNode { range: name.range.start..value.range.end, node: Parameter { name, value }, path: no_path() } } rule parameters() -> Vec> = v:(parameter() **<1,> list_separator()) list_separator()? { v } @@ -234,7 +242,7 @@ peg::parser! { rule name_value_pair() -> AstNode = name:ident() __ "=" __ value:expr() - { AstNode { range: name.start..value.range.end, node: NameValuePair { name, value } } } + { AstNode { range: name.range.start..value.range.end, node: NameValuePair { name, value }, path: no_path() } } rule name_value_pairs() -> Vec> = v:(name_value_pair() **<1,> list_separator()) list_separator()? { v } @@ -242,11 +250,11 @@ peg::parser! { rule struct_t() -> AstNode = t:$"struct" __ "{" __ fields:fields() __ e:$"}" - { AstNode { range: t.start..e.end, node: Expr::Struct { fields, struct_tok: t } } } + { AstNode { range: t.start..e.end, node: Expr::Struct { fields, struct_tok: t }, path: no_path() } } rule field() -> AstNode = s:position!() public:$"pub"? __ mutable:$"mut"? __ name:ident() __ ":" __ ty:expr() e:position!() - { AstNode { node: Field { name, ty, public, mutable }, range: s..e } } + { AstNode { node: Field { name, ty, public, mutable }, range: s..e, path: no_path() } } rule fields() -> Vec> = v:(field() **<1,> list_separator()) list_separator()? { v } @@ -254,31 +262,31 @@ peg::parser! { rule import() -> AstNode = t:$"import" _ expr:expr() - { AstNode { range: t.start..expr.range.end, node: Import { import_tok: t, expr } } } + { AstNode { range: t.start..expr.range.end, node: Import { import_tok: t, expr }, path: no_path() } } rule name_pattern() -> AstNode = s:$"(" __ tuple:(ident() ** ("," __)) __ e:$")" - { AstNode { range: s.start..e.end, node: NamePattern::Tuple(tuple) } } + { AstNode { range: s.start..e.end, node: NamePattern::Tuple(tuple), path: no_path() } } / s:$"[" __ slice:(ident() ** ("," __)) __ e:$"]" - { AstNode { range: s.start..e.end, node: NamePattern::List(slice) } } - / ident:ident() - { AstNode { range: ident.clone(), node: NamePattern::Single(ident) } } + { AstNode { range: s.start..e.end, node: NamePattern::List(slice), path: no_path() } } + / i:ident() + { AstNode { range: i.range.clone(), node: NamePattern::Single(i), path: no_path() } } rule const_decl() -> AstNode = names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? ":" _ value:expr() - { AstNode { range: names.range.start..value.range.end, node: ConstDecl { names, r#type, value } } } + { AstNode { range: names.range.start..value.range.end, node: ConstDecl { names, r#type, value }, path: no_path() } } rule var_decl() -> AstNode = names:name_pattern() _? ":" r#type:(_ t:expr() _ {t})? "=" _ value:expr() - { AstNode { range: names.range.start..value.range.end, node: VarDecl { names, r#type, value } } } + { AstNode { range: names.range.start..value.range.end, node: VarDecl { names, r#type, value }, path: no_path() } } rule while_loop() -> AstNode = t:$"while" _ cond:expr() _ block:block() - { AstNode { range: t.start..block.range.end, node: While { cond, block, while_tok: t } } } + { AstNode { range: t.start..block.range.end, node: While { cond, block, while_tok: t }, path: no_path() } } rule if_statement() -> AstNode = t:$"if" _ cond:expr() __ block:block() el:(__ e:else_statement() {e})? e:position!() - { AstNode { range: t.start..e, node: If { cond, block, else_: el.map(Box::new), if_tok: t } } } + { AstNode { range: t.start..e, node: If { cond, block, else_: el.map(Box::new), if_tok: t }, path: no_path() } } rule else_statement() -> Else = t:$"else" _ i:if_statement() { Else::If { else_tok: t, expr: i } } diff --git a/parser/src/path.rs b/parser/src/path.rs new file mode 100644 index 0000000..e5acc3a --- /dev/null +++ b/parser/src/path.rs @@ -0,0 +1,308 @@ +use crate::ast::*; +use std::sync::Arc; + +pub(crate) trait ComputePaths { + fn compute_paths(&mut self, path: &mut Vec); +} + +impl ComputePaths for AstRoot { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + for decl in &mut self.decls { + path.push(id.next().unwrap()); + decl.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for AstNode<()> { + fn compute_paths(&mut self, path: &mut Vec) { + self.path = Arc::from_iter(path.iter().cloned()); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + self.path = Arc::from_iter(path.iter().cloned()); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + + path.push(id.next().unwrap()); + self.node.names.compute_paths(path); + path.pop(); + + if let Some(ty) = &mut self.node.r#type { + path.push(id.next().unwrap()); + ty.compute_paths(path); + path.pop(); + } + path.push(id.next().unwrap()); + self.node.value.compute_paths(path); + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + + path.push(id.next().unwrap()); + self.node.names.compute_paths(path); + path.pop(); + + if let Some(ty) = &mut self.node.r#type { + path.push(id.next().unwrap()); + ty.compute_paths(path); + path.pop(); + } + path.push(id.next().unwrap()); + self.node.value.compute_paths(path); + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + for name in self.node.as_mut_slice() { + path.push(id.next().unwrap()); + name.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for Number { + fn compute_paths(&mut self, path: &mut Vec) { + if let Some(ty) = &mut self.ty { + path.push(0); + ty.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + match &mut self.node { + Expr::Ident => {} + Expr::Number(n) => { + n.compute_paths(path); + } + Expr::VarDecl(decl) => { + decl.compute_paths(path); + } + Expr::ConstDecl(decl) => { + decl.compute_paths(path); + } + Expr::Func(func) => { + let func = Arc::get_mut(func).unwrap(); + func.compute_paths(path); + } + Expr::Ptr { base, .. } => { + path.push(id.next().unwrap()); + base.compute_paths(path); + path.pop(); + } + Expr::Struct { fields, .. } => { + for field in fields { + path.push(id.next().unwrap()); + field.compute_paths(path); + path.pop(); + } + } + Expr::StructCtor { ty, values } => { + if let Some(ty) = ty { + path.push(id.next().unwrap()); + ty.compute_paths(path); + path.pop(); + } + for value in values { + path.push(id.next().unwrap()); + value.compute_paths(path); + path.pop(); + } + } + Expr::Binary { lhs, operator, rhs } => { + path.push(id.next().unwrap()); + lhs.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + operator.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + rhs.compute_paths(path); + path.pop(); + } + Expr::Access { value, field, .. } => { + path.push(id.next().unwrap()); + value.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + field.compute_paths(path); + path.pop(); + } + Expr::Deref { value, .. } => { + path.push(id.next().unwrap()); + value.compute_paths(path); + path.pop(); + } + Expr::Call { func, args } => { + path.push(id.next().unwrap()); + func.compute_paths(path); + path.pop(); + + for arg in args { + path.push(id.next().unwrap()); + arg.compute_paths(path); + path.pop(); + } + } + Expr::If(expr) => { + expr.compute_paths(path); + } + Expr::While(expr) => { + expr.compute_paths(path); + } + _ => todo!("{self:#?}"), + } + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + + path.push(id.next().unwrap()); + self.node.cond.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + self.node.block.compute_paths(path); + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + + path.push(id.next().unwrap()); + self.node.cond.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + self.node.block.compute_paths(path); + path.pop(); + + if let Some(else_) = &mut self.node.else_ { + path.push(id.next().unwrap()); + else_.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for Else { + fn compute_paths(&mut self, path: &mut Vec) { + path.push(0); + match self { + Else::If { expr, .. } => expr.compute_paths(path), + Else::Block { expr, .. } => expr.compute_paths(path), + } + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + + path.push(id.next().unwrap()); + self.node.name.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + self.node.value.compute_paths(path); + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + for arg in &mut self.node.args { + path.push(id.next().unwrap()); + arg.compute_paths(path); + path.pop(); + } + if let Some(ret) = &mut self.node.ret { + path.push(id.next().unwrap()); + ret.compute_paths(path); + path.pop(); + } + if let Some(block) = &mut self.node.block { + let block = Arc::get_mut(block).unwrap(); + path.push(id.next().unwrap()); + block.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + for expr in self.node.0.iter_mut() { + path.push(id.next().unwrap()); + expr.compute_paths(path); + path.pop(); + } + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + + path.push(id.next().unwrap()); + self.node.name.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + self.node.value.compute_paths(path); + path.pop(); + } +} + +impl ComputePaths for AstNode { + fn compute_paths(&mut self, path: &mut Vec) { + let mut id = 0..; + self.path = Arc::from_iter(path.iter().cloned()); + + path.push(id.next().unwrap()); + self.node.name.compute_paths(path); + path.pop(); + + path.push(id.next().unwrap()); + self.node.ty.compute_paths(path); + path.pop(); + } +}