Compilation aided syntax highlighting
This commit is contained in:
@@ -29,6 +29,8 @@ pub enum Code {
|
||||
InvalidCast = 0x0207,
|
||||
CannotDereference = 0x0209,
|
||||
CannotInferType = 0x020A,
|
||||
InvalidOperation = 0x020B,
|
||||
InvalidParameterCount = 0x020C,
|
||||
|
||||
UninitializedField = 0x0300,
|
||||
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -32,3 +32,15 @@ impl CodePosition {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CodePath {
|
||||
pub file: Arc<SourceCode>,
|
||||
pub path: Arc<[u32]>,
|
||||
}
|
||||
|
||||
impl CodePath {
|
||||
pub fn new(file: Arc<SourceCode>, path: Arc<[u32]>) -> Self {
|
||||
Self { file, path }
|
||||
}
|
||||
}
|
||||
|
||||
+62
-29
@@ -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<ConstDecl>]) {
|
||||
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<AnyValue<'l>, 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!(),
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
@@ -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<Diagnostic>,
|
||||
}
|
||||
|
||||
pub fn parse_document(code: &Arc<SourceCode>) -> DocumentParsingResult {
|
||||
impl Default for DocumentSyntax {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tokens: SemanticTokensResult::Tokens(SemanticTokens::default()),
|
||||
diagnostics: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_syntax_tokens(
|
||||
code: &Arc<SourceCode>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) -> 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<SourceCode>) -> 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<SourceCode>) -> DocumentParsingResult {
|
||||
size as f32 / 1000.0,
|
||||
now.elapsed()
|
||||
);
|
||||
DocumentParsingResult {
|
||||
DocumentSyntax {
|
||||
tokens: SemanticTokensResult::Tokens(tokens),
|
||||
diagnostics: vec![],
|
||||
}
|
||||
@@ -90,6 +106,7 @@ trait PushSemanticTokens {
|
||||
file: &Arc<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
hint: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,24 +116,44 @@ impl PushSemanticTokens for AstNode<ConstDecl> {
|
||||
file: &Arc<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
hint: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
hint: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<Expr> {
|
||||
file: &Arc<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
hint: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<Expr> {
|
||||
..
|
||||
} 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<Expr> {
|
||||
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<Expr> {
|
||||
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<Expr> {
|
||||
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<Expr> {
|
||||
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<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
_: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
_: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
_: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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<SourceCode>,
|
||||
tokens: &mut SemanticTokens,
|
||||
_: Option<u32>,
|
||||
symbols: &HashMap<Arc<[u32]>, [u8; size_of::<AnyValue>()]>,
|
||||
) {
|
||||
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::<AnyValue>()]) -> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
-103
@@ -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<HashMap<Uri, (Rope, i32)>>,
|
||||
file_code: Mutex<HashMap<Uri, (Arc<SourceCode>, i32)>>,
|
||||
file_docs: Mutex<HashMap<Uri, Arc<DocumentSyntax>>>,
|
||||
compilation_state: Arc<Mutex<CompilationState>>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn with_file_text<T>(&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<T>(
|
||||
&self,
|
||||
uri: Uri,
|
||||
action: impl FnOnce(&mut (Arc<SourceCode>, 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<Arc<Workspace>, 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::<Uri, (Rope, i32)>::new();
|
||||
let mut files = HashMap::<Uri, (Arc<SourceCode>, i32)>::new();
|
||||
let mut parsed = HashMap::<Uri, DocumentParsingResult>::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(
|
||||
|
||||
+23
-14
@@ -22,6 +22,7 @@ pub enum BinaryOperator {
|
||||
|
||||
#[derive(Debug, Deref, Clone)]
|
||||
pub struct AstNode<T> {
|
||||
pub path: Arc<[u32]>,
|
||||
pub range: Range<usize>,
|
||||
#[deref]
|
||||
pub node: T,
|
||||
@@ -30,27 +31,27 @@ pub struct AstNode<T> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Number {
|
||||
pub number: Range<usize>,
|
||||
pub ty: Option<Range<usize>>,
|
||||
pub ty: Option<AstNode<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expr {
|
||||
Number(Number),
|
||||
String(Range<usize>),
|
||||
Ident(Range<usize>),
|
||||
Ident,
|
||||
Uninit(Range<usize>),
|
||||
If(Box<If>),
|
||||
If(Box<AstNode<If>>),
|
||||
Func(Arc<AstNode<Function>>),
|
||||
While(Box<While>),
|
||||
While(Box<AstNode<While>>),
|
||||
Block(Arc<AstNode<Block>>),
|
||||
VarDecl(Box<VarDecl>),
|
||||
ConstDecl(Box<ConstDecl>),
|
||||
VarDecl(Box<AstNode<VarDecl>>),
|
||||
ConstDecl(Box<AstNode<ConstDecl>>),
|
||||
List(Vec<AstNode<Expr>>),
|
||||
Tuple(Vec<AstNode<Expr>>),
|
||||
Access {
|
||||
value: Box<AstNode<Expr>>,
|
||||
operator: Range<usize>,
|
||||
field: Range<usize>,
|
||||
field: AstNode<()>,
|
||||
},
|
||||
Deref {
|
||||
value: Box<AstNode<Expr>>,
|
||||
@@ -97,7 +98,7 @@ pub struct Import {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Field {
|
||||
pub name: Range<usize>,
|
||||
pub name: AstNode<()>,
|
||||
pub ty: AstNode<Expr>,
|
||||
pub public: Option<Range<usize>>,
|
||||
pub mutable: Option<Range<usize>>,
|
||||
@@ -105,19 +106,27 @@ pub struct Field {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum NamePattern {
|
||||
Single(Range<usize>),
|
||||
Tuple(Vec<Range<usize>>),
|
||||
List(Vec<Range<usize>>),
|
||||
Single(AstNode<()>),
|
||||
Tuple(Vec<AstNode<()>>),
|
||||
List(Vec<AstNode<()>>),
|
||||
}
|
||||
|
||||
impl NamePattern {
|
||||
pub fn as_slice(&self) -> &[Range<usize>] {
|
||||
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<usize>,
|
||||
pub name: AstNode<()>,
|
||||
pub value: AstNode<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NameValuePair {
|
||||
pub name: Range<usize>,
|
||||
pub name: AstNode<()>,
|
||||
pub value: AstNode<Expr>,
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -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<RangeMap<usize, (usize, Substr)>>),
|
||||
ArcStr(ArcStr, OnceLock<RangeMap<usize, (usize, Range<usize>)>>),
|
||||
}
|
||||
|
||||
pub struct SourceCode {
|
||||
@@ -68,3 +70,9 @@ impl Debug for SourceCode {
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(src: &SourceCode) -> Result<AstRoot, ParseError<LineCol>> {
|
||||
let mut ast = compilation_unit(src)?;
|
||||
ast.compute_paths(&mut vec![]);
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
+73
-65
@@ -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<Arc<[u32]>> = OnceLock::new();
|
||||
ARC.get_or_init(Arc::default).clone()
|
||||
}
|
||||
|
||||
peg::parser! {
|
||||
grammar leaf_parser() for SourceCode {
|
||||
// #### ATOMS ####
|
||||
rule number() -> AstNode<Number>
|
||||
= 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<usize>
|
||||
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<usize>
|
||||
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<usize>
|
||||
= text:$("\"" [^'\\'|'"']* "\"")
|
||||
@@ -127,106 +135,106 @@ peg::parser! {
|
||||
// ### EXPRESSIONS ####
|
||||
|
||||
rule bop0() -> AstNode<BinaryOperator>
|
||||
= 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<BinaryOperator>
|
||||
= 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<BinaryOperator>
|
||||
= 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<BinaryOperator>
|
||||
= 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<BinaryOperator>
|
||||
= op:$("..") { AstNode { range: op, node: BinaryOperator::Range } }
|
||||
= op:$("..") { AstNode { range: op, node: BinaryOperator::Range, path: no_path() } }
|
||||
|
||||
rule expr() -> AstNode<Expr> = 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<Block>
|
||||
= 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<Function>
|
||||
= 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<Parameter>
|
||||
= 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<AstNode<Parameter>>
|
||||
= v:(parameter() **<1,> list_separator()) list_separator()? { v }
|
||||
@@ -234,7 +242,7 @@ peg::parser! {
|
||||
|
||||
rule name_value_pair() -> AstNode<NameValuePair>
|
||||
= 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<AstNode<NameValuePair>>
|
||||
= v:(name_value_pair() **<1,> list_separator()) list_separator()? { v }
|
||||
@@ -242,11 +250,11 @@ peg::parser! {
|
||||
|
||||
rule struct_t() -> AstNode<Expr>
|
||||
= 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<Field>
|
||||
= 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<AstNode<Field>>
|
||||
= v:(field() **<1,> list_separator()) list_separator()? { v }
|
||||
@@ -254,31 +262,31 @@ peg::parser! {
|
||||
|
||||
rule import() -> AstNode<Import>
|
||||
= 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<NamePattern>
|
||||
= 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<ConstDecl> =
|
||||
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<VarDecl> =
|
||||
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<While>
|
||||
= 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<If>
|
||||
= 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 } }
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
use crate::ast::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) trait ComputePaths {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>);
|
||||
}
|
||||
|
||||
impl ComputePaths for AstRoot {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<u32>) {
|
||||
self.path = Arc::from_iter(path.iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputePaths for AstNode<BinaryOperator> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
self.path = Arc::from_iter(path.iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputePaths for AstNode<ConstDecl> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<VarDecl> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<NamePattern> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<u32>) {
|
||||
if let Some(ty) = &mut self.ty {
|
||||
path.push(0);
|
||||
ty.compute_paths(path);
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputePaths for AstNode<Expr> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<While> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<If> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<u32>) {
|
||||
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<NameValuePair> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<Function> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<Block> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<Parameter> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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<Field> {
|
||||
fn compute_paths(&mut self, path: &mut Vec<u32>) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user