mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
Refactor diagnostic: Merge BuildDiagnostic and FileDiagnostic
This commit is contained in:
parent
11e0be5130
commit
730b1ccff2
19 changed files with 313 additions and 480 deletions
|
@ -54,6 +54,8 @@ use std::env;
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use sixtyfps_compilerlib::diagnostics::BuildDiagnostics;
|
||||
|
||||
/// The structure for configuring aspects of the compilation of `.60` markup files to Rust.
|
||||
pub struct CompilerConfiguration {
|
||||
config: sixtyfps_compilerlib::CompilerConfiguration,
|
||||
|
@ -180,8 +182,9 @@ pub fn compile_with_config(
|
|||
let path = Path::new(&env::var_os("CARGO_MANIFEST_DIR").ok_or(CompileError::NotRunViaCargo)?)
|
||||
.join(path.as_ref());
|
||||
|
||||
let (syntax_node, diag) =
|
||||
sixtyfps_compilerlib::parser::parse_file(&path).map_err(CompileError::LoadError)?;
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = sixtyfps_compilerlib::parser::parse_file(&path, &mut diag)
|
||||
.map_err(CompileError::LoadError)?;
|
||||
|
||||
if diag.has_error() {
|
||||
let vec = diag.to_string_vec();
|
||||
|
@ -222,7 +225,7 @@ pub fn compile_with_config(
|
|||
let mut code_formater = CodeFormatter { indentation: 0, in_string: false, sink: file };
|
||||
let generated = match sixtyfps_compilerlib::generator::rust::generate(&doc, &mut diag) {
|
||||
Some(code) => {
|
||||
for x in diag.files() {
|
||||
for x in &diag.all_loaded_files {
|
||||
if x.is_absolute() {
|
||||
println!("cargo:rerun-if-changed={}", x.display());
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ You should use the `sixtyfps` crate instead.
|
|||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::{Spacing, TokenStream, TokenTree};
|
||||
use quote::{quote, ToTokens};
|
||||
use quote::quote;
|
||||
use sixtyfps_compilerlib::diagnostics::BuildDiagnostics;
|
||||
use sixtyfps_compilerlib::parser::SyntaxKind;
|
||||
use sixtyfps_compilerlib::*;
|
||||
|
||||
|
@ -319,10 +320,10 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
|
|||
let mut tokens = vec![];
|
||||
fill_token_vec(token_iter, &mut tokens);
|
||||
|
||||
let (syntax_node, mut diag) = parser::parse_tokens(tokens.clone());
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = parser::parse_tokens(tokens.clone(), &mut diag);
|
||||
if diag.has_error() {
|
||||
diag.map_offsets_to_span(&tokens);
|
||||
return diag.into_token_stream().into();
|
||||
return diag.report_macro_diagnostic(&tokens);
|
||||
}
|
||||
|
||||
let source_file = if let Some(cargo_manifest) = std::env::var_os("CARGO_MANIFEST_DIR") {
|
||||
|
@ -343,14 +344,15 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
|
|||
spin_on::spin_on(compile_syntax_node(syntax_node, diag, compiler_config));
|
||||
//println!("{:#?}", tree);
|
||||
if diag.has_error() {
|
||||
return report_diagnostics(diag, &tokens);
|
||||
return diag.report_macro_diagnostic(&tokens);
|
||||
}
|
||||
|
||||
let mut result = generator::rust::generate(&root_component, &mut diag);
|
||||
|
||||
// Make sure to recompile if any of the external files changes
|
||||
let reload = diag
|
||||
.files()
|
||||
.all_loaded_files
|
||||
.iter()
|
||||
.filter(|path| path.is_absolute() && !path.ends_with("Cargo.toml"))
|
||||
.filter_map(|p| p.to_str())
|
||||
.map(|p| quote! {const _ : &'static [u8] = ::core::include_bytes!(#p);});
|
||||
|
@ -359,27 +361,6 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
|
|||
x.extend(quote! {const _ : Option<&'static str> = ::core::option_env!("SIXTYFPS_STYLE");});
|
||||
});
|
||||
|
||||
let diags = report_diagnostics(diag, &tokens);
|
||||
let diags = diag.report_macro_diagnostic(&tokens);
|
||||
result.map_or(diags, |r| r.into())
|
||||
}
|
||||
|
||||
fn report_diagnostics(
|
||||
diag: diagnostics::BuildDiagnostics,
|
||||
span_map: &[parser::Token],
|
||||
) -> TokenStream {
|
||||
let mut result = TokenStream::new();
|
||||
let mut needs_error = diag.has_error();
|
||||
for mut file_diag in diag.into_iter() {
|
||||
if file_diag.current_path.path() == std::path::PathBuf::default() {
|
||||
file_diag.map_offsets_to_span(span_map);
|
||||
needs_error &= !file_diag.has_error();
|
||||
result.extend(TokenStream::from(file_diag.into_token_stream()))
|
||||
} else {
|
||||
file_diag.print();
|
||||
}
|
||||
}
|
||||
if needs_error {
|
||||
result.extend(TokenStream::from(quote!(compile_error! { "Error occured" })))
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
@ -77,37 +77,33 @@ pub async fn compile_from_string(
|
|||
let level_key = JsValue::from_str("level");
|
||||
let mut error_as_string = String::new();
|
||||
let array = js_sys::Array::new();
|
||||
for diag in errors.into_iter() {
|
||||
let filename_js = JsValue::from_str(&diag.current_path.display().to_string());
|
||||
for d in &diag.inner {
|
||||
if !error_as_string.is_empty() {
|
||||
error_as_string.push_str("\n");
|
||||
}
|
||||
use std::fmt::Write;
|
||||
for d in errors.into_iter() {
|
||||
let filename = d
|
||||
.span
|
||||
.source_file
|
||||
.as_ref()
|
||||
.map_or(String::new(), |sf| sf.path().to_string_lossy().into());
|
||||
|
||||
let (line, column) = d.line_column(&diag);
|
||||
write!(&mut error_as_string, "{}:{}:{}", diag.current_path.display(), line, d)
|
||||
.unwrap();
|
||||
let error_obj = js_sys::Object::new();
|
||||
js_sys::Reflect::set(
|
||||
&error_obj,
|
||||
&message_key,
|
||||
&JsValue::from_str(&d.to_string()),
|
||||
)?;
|
||||
js_sys::Reflect::set(&error_obj, &line_key, &JsValue::from_f64(line as f64))?;
|
||||
js_sys::Reflect::set(
|
||||
&error_obj,
|
||||
&column_key,
|
||||
&JsValue::from_f64(column as f64),
|
||||
)?;
|
||||
js_sys::Reflect::set(&error_obj, &file_key, &filename_js)?;
|
||||
js_sys::Reflect::set(
|
||||
&error_obj,
|
||||
&level_key,
|
||||
&JsValue::from_f64(d.level() as i8 as f64),
|
||||
)?;
|
||||
array.push(&error_obj);
|
||||
let filename_js = JsValue::from_str(&filename);
|
||||
|
||||
if !error_as_string.is_empty() {
|
||||
error_as_string.push_str("\n");
|
||||
}
|
||||
use std::fmt::Write;
|
||||
|
||||
let (line, column) = d.line_column();
|
||||
write!(&mut error_as_string, "{}:{}:{}", filename, line, d).unwrap();
|
||||
let error_obj = js_sys::Object::new();
|
||||
js_sys::Reflect::set(&error_obj, &message_key, &JsValue::from_str(&d.message))?;
|
||||
js_sys::Reflect::set(&error_obj, &line_key, &JsValue::from_f64(line as f64))?;
|
||||
js_sys::Reflect::set(&error_obj, &column_key, &JsValue::from_f64(column as f64))?;
|
||||
js_sys::Reflect::set(&error_obj, &file_key, &filename_js)?;
|
||||
js_sys::Reflect::set(
|
||||
&error_obj,
|
||||
&level_key,
|
||||
&JsValue::from_f64(d.level() as i8 as f64),
|
||||
)?;
|
||||
array.push(&error_obj);
|
||||
}
|
||||
|
||||
let error = js_sys::Error::new(&error_as_string);
|
||||
|
|
|
@ -11,12 +11,12 @@ use std::collections::HashMap;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// Span represent an error location within a file.
|
||||
///
|
||||
/// Currently, it is just an offset in byte within the file.
|
||||
///
|
||||
/// When the `proc_macro_span` feature is enabled, it may also hold a proc_maco span.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Span {
|
||||
pub offset: usize,
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
|
@ -108,14 +108,8 @@ pub type SourceFile = Rc<SourceFileInner>;
|
|||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SourceLocation {
|
||||
source_file: Option<SourceFile>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl From<SyntaxNodeWithSourceFile> for SourceLocation {
|
||||
fn from(node: SyntaxNodeWithSourceFile) -> Self {
|
||||
SourceLocation { span: node.span(), source_file: node.source_file }
|
||||
}
|
||||
pub source_file: Option<SourceFile>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Spanned for SourceLocation {
|
||||
|
@ -161,39 +155,23 @@ impl From<DiagnosticLevel> for codemap_diagnostic::Level {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Default, Debug)]
|
||||
#[error("{message}")]
|
||||
pub struct CompilerDiagnostic {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Diagnostic {
|
||||
pub message: String,
|
||||
pub span: SourceLocation,
|
||||
pub level: DiagnosticLevel,
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Diagnostic {
|
||||
#[error(transparent)]
|
||||
FileLoadError(#[from] std::io::Error),
|
||||
#[error(transparent)]
|
||||
CompilerDiagnostic(#[from] CompilerDiagnostic),
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
/// Return the level for this diagnostic
|
||||
pub fn level(&self) -> DiagnosticLevel {
|
||||
match self {
|
||||
Diagnostic::CompilerDiagnostic(e) => e.level,
|
||||
_ => DiagnosticLevel::Error,
|
||||
}
|
||||
self.level
|
||||
}
|
||||
|
||||
/// Returns a tuple with the line (starting at 1) and column number (starting at 0)
|
||||
pub fn line_column(&self) -> (usize, usize) {
|
||||
let source_location = match self {
|
||||
Diagnostic::CompilerDiagnostic(e) => &e.span,
|
||||
_ => return (0, 0),
|
||||
};
|
||||
let offset = source_location.span.offset;
|
||||
let line_offsets = match &source_location.source_file {
|
||||
let offset = self.span.span.offset;
|
||||
let line_offsets = match &self.span.source_file {
|
||||
None => return (0, 0),
|
||||
Some(sl) => sl.line_offsets(),
|
||||
};
|
||||
|
@ -210,16 +188,29 @@ impl Diagnostic {
|
|||
}
|
||||
}
|
||||
|
||||
/// This structure holds all the diagnostics for a given files
|
||||
#[derive(Default, Debug)]
|
||||
pub struct FileDiagnostics {
|
||||
/// List of diagnostics related to this file
|
||||
pub inner: Vec<Diagnostic>,
|
||||
/// file path
|
||||
pub current_path: SourceFile,
|
||||
impl std::fmt::Display for Diagnostic {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(sf) = self.span.source_file() {
|
||||
let (line, _) = self.line_column();
|
||||
write!(f, "{}:{}: {}", sf.path.display(), line, self.message)
|
||||
} else {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for FileDiagnostics {
|
||||
#[derive(Default)]
|
||||
pub struct BuildDiagnostics {
|
||||
inner: Vec<Diagnostic>,
|
||||
|
||||
/// This is the list of all loaded files (with or without diagnostic)
|
||||
/// does not include the main file.
|
||||
/// FIXME: this doesn't really belong in the diagnostics, it should be somehow returned in another way
|
||||
/// (maybe in a compilation state that include the diagnostics?)
|
||||
pub all_loaded_files: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl IntoIterator for BuildDiagnostics {
|
||||
type Item = Diagnostic;
|
||||
type IntoIter = <Vec<Diagnostic> as IntoIterator>::IntoIter;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
|
@ -227,23 +218,22 @@ impl IntoIterator for FileDiagnostics {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileDiagnostics {
|
||||
impl BuildDiagnostics {
|
||||
pub fn push_diagnostic_with_span(
|
||||
&mut self,
|
||||
message: String,
|
||||
span: Span,
|
||||
span: SourceLocation,
|
||||
level: DiagnosticLevel,
|
||||
) {
|
||||
let span = SourceLocation { source_file: Some(self.current_path.clone()), span };
|
||||
self.inner.push(CompilerDiagnostic { message, span, level }.into());
|
||||
self.inner.push(Diagnostic { message, span, level }.into());
|
||||
}
|
||||
pub fn push_error_with_span(&mut self, message: String, span: Span) {
|
||||
pub fn push_error_with_span(&mut self, message: String, span: SourceLocation) {
|
||||
self.push_diagnostic_with_span(message, span, DiagnosticLevel::Error)
|
||||
}
|
||||
pub fn push_error(&mut self, message: String, source: &dyn Spanned) {
|
||||
self.push_error_with_span(message, source.span());
|
||||
self.push_error_with_span(message, source.to_source_location());
|
||||
}
|
||||
pub fn push_compiler_error(&mut self, error: CompilerDiagnostic) {
|
||||
pub fn push_compiler_error(&mut self, error: Diagnostic) {
|
||||
self.inner.push(error.into());
|
||||
}
|
||||
|
||||
|
@ -258,17 +248,14 @@ impl FileDiagnostics {
|
|||
"The property '{}' has been deprecated. Please use '{}' instead",
|
||||
old_property, new_property
|
||||
),
|
||||
source.span(),
|
||||
source.to_source_location(),
|
||||
crate::diagnostics::DiagnosticLevel::Warning,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return true if there is at least one compilation error for this file
|
||||
pub fn has_error(&self) -> bool {
|
||||
self.inner.iter().any(|diag| match diag {
|
||||
Diagnostic::FileLoadError(_) => true,
|
||||
Diagnostic::CompilerDiagnostic(diag) => matches!(diag.level, DiagnosticLevel::Error),
|
||||
})
|
||||
self.inner.iter().any(|diag| diag.level == DiagnosticLevel::Error)
|
||||
}
|
||||
|
||||
/// Return true if there are no diagnostics (warnings or errors); false otherwise.
|
||||
|
@ -280,6 +267,7 @@ impl FileDiagnostics {
|
|||
fn call_diagnostics<'a, Output>(
|
||||
self,
|
||||
output: &'a mut Output,
|
||||
mut handle_no_source: Option<&mut dyn FnMut(Diagnostic)>,
|
||||
emitter_factory: impl for<'b> FnOnce(
|
||||
&'b mut Output,
|
||||
Option<&'b codemap::CodeMap>,
|
||||
|
@ -290,42 +278,43 @@ impl FileDiagnostics {
|
|||
}
|
||||
|
||||
let mut codemap = codemap::CodeMap::new();
|
||||
let internal_errors = self.current_path.source.is_none();
|
||||
let file = codemap.add_file(
|
||||
self.current_path.path.to_string_lossy().to_string(),
|
||||
self.current_path.source.clone().unwrap_or_default(),
|
||||
);
|
||||
let file_span = file.span;
|
||||
let mut codemap_files = HashMap::new();
|
||||
|
||||
let diags: Vec<_> = self
|
||||
.inner
|
||||
.into_iter()
|
||||
.map(|diagnostic| match diagnostic {
|
||||
Diagnostic::CompilerDiagnostic(CompilerDiagnostic { message, span, level }) => {
|
||||
let spans = if !internal_errors && span.span.is_valid() {
|
||||
let s = codemap_diagnostic::SpanLabel {
|
||||
span: file_span
|
||||
.subspan(span.span.offset as u64, span.span.offset as u64),
|
||||
style: codemap_diagnostic::SpanStyle::Primary,
|
||||
label: None,
|
||||
};
|
||||
vec![s]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
codemap_diagnostic::Diagnostic {
|
||||
level: level.into(),
|
||||
message,
|
||||
code: None,
|
||||
spans,
|
||||
.filter_map(|d| {
|
||||
let spans = if let Some(sf) = &d.span.source_file {
|
||||
if let Some(ref mut handle_no_source) = handle_no_source {
|
||||
if sf.source.is_none() {
|
||||
handle_no_source(d);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Diagnostic::FileLoadError(err) => codemap_diagnostic::Diagnostic {
|
||||
level: codemap_diagnostic::Level::Error,
|
||||
message: err.to_string(),
|
||||
let path: String = sf.path.to_string_lossy().into();
|
||||
let file = codemap_files.entry(path).or_insert_with(|| {
|
||||
codemap.add_file(
|
||||
sf.path.to_string_lossy().into(),
|
||||
sf.source.clone().unwrap_or_default(),
|
||||
)
|
||||
});
|
||||
let file_span = file.span;
|
||||
let s = codemap_diagnostic::SpanLabel {
|
||||
span: file_span
|
||||
.subspan(d.span.span.offset as u64, d.span.span.offset as u64),
|
||||
style: codemap_diagnostic::SpanStyle::Primary,
|
||||
label: None,
|
||||
};
|
||||
vec![s]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
Some(codemap_diagnostic::Diagnostic {
|
||||
level: d.level.into(),
|
||||
message: d.message,
|
||||
code: None,
|
||||
spans: vec![],
|
||||
},
|
||||
spans,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -336,7 +325,7 @@ impl FileDiagnostics {
|
|||
#[cfg(feature = "display-diagnostics")]
|
||||
/// Print the diagnostics on the console
|
||||
pub fn print(self) {
|
||||
self.call_diagnostics(&mut (), |_, codemap| {
|
||||
self.call_diagnostics(&mut (), None, |_, codemap| {
|
||||
codemap_diagnostic::Emitter::stderr(codemap_diagnostic::ColorConfig::Always, codemap)
|
||||
});
|
||||
}
|
||||
|
@ -345,7 +334,7 @@ impl FileDiagnostics {
|
|||
/// Print into a string
|
||||
pub fn diagnostics_as_string(self) -> String {
|
||||
let mut output = Vec::new();
|
||||
self.call_diagnostics(&mut output, |output, codemap| {
|
||||
self.call_diagnostics(&mut output, None, |output, codemap| {
|
||||
codemap_diagnostic::Emitter::vec(output, codemap)
|
||||
});
|
||||
|
||||
|
@ -354,182 +343,79 @@ impl FileDiagnostics {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
#[cfg(all(feature = "proc_macro_span", feature = "display-diagnostics"))]
|
||||
/// Will convert the diagnostics that only have offsets to the actual proc_macro::Span
|
||||
pub fn map_offsets_to_span(&mut self, span_map: &[crate::parser::Token]) {
|
||||
for d in &mut self.inner {
|
||||
if let Diagnostic::CompilerDiagnostic(d) = d {
|
||||
if d.span.span.span.is_none() {
|
||||
pub fn report_macro_diagnostic(
|
||||
self,
|
||||
span_map: &[crate::parser::Token],
|
||||
) -> proc_macro::TokenStream {
|
||||
let mut result = proc_macro::TokenStream::default();
|
||||
let mut needs_error = self.has_error();
|
||||
self.call_diagnostics(
|
||||
&mut (),
|
||||
Some(&mut |diag| {
|
||||
let span = diag.span.span.span.clone().or_else(|| {
|
||||
//let pos =
|
||||
//span_map.binary_search_by_key(d.span.offset, |x| x.0).unwrap_or_else(|x| x);
|
||||
//d.span.span = span_map.get(pos).as_ref().map(|x| x.1);
|
||||
let mut offset = 0;
|
||||
d.span.span.span = span_map.iter().find_map(|t| {
|
||||
if d.span.span.offset <= offset {
|
||||
span_map.iter().find_map(|t| {
|
||||
if diag.span.span.offset <= offset {
|
||||
t.span
|
||||
} else {
|
||||
offset += t.text.len();
|
||||
None
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
let message = &diag.message;
|
||||
match diag.level {
|
||||
DiagnosticLevel::Error => {
|
||||
needs_error = false;
|
||||
result.extend(proc_macro::TokenStream::from(if let Some(span) = span {
|
||||
quote::quote_spanned!(span.into() => compile_error!{ #message })
|
||||
} else {
|
||||
quote::quote!(compile_error! { #message })
|
||||
}));
|
||||
}
|
||||
// FIXME: find a way to report warnings.
|
||||
DiagnosticLevel::Warning => (),
|
||||
}
|
||||
}
|
||||
}),
|
||||
|_, codemap| {
|
||||
codemap_diagnostic::Emitter::stderr(
|
||||
codemap_diagnostic::ColorConfig::Always,
|
||||
codemap,
|
||||
)
|
||||
},
|
||||
);
|
||||
if needs_error {
|
||||
result.extend(proc_macro::TokenStream::from(quote::quote!(
|
||||
compile_error! { "Error occured" }
|
||||
)))
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn to_string_vec(&self) -> Vec<String> {
|
||||
self.inner.iter().map(|d| d.to_string()).collect()
|
||||
}
|
||||
|
||||
pub fn new_from_error(path: std::path::PathBuf, err: std::io::Error) -> Self {
|
||||
Self { inner: vec![err.into()], current_path: SourceFileInner::from_path(path) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
use quote::quote;
|
||||
|
||||
use crate::parser::SyntaxNodeWithSourceFile;
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
impl quote::ToTokens for FileDiagnostics {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
let diags: Vec<_> = self
|
||||
.inner
|
||||
.iter()
|
||||
.filter_map(|diag| match diag {
|
||||
Diagnostic::CompilerDiagnostic(CompilerDiagnostic {
|
||||
level,
|
||||
message,
|
||||
span,
|
||||
}) => {
|
||||
match level {
|
||||
DiagnosticLevel::Error => {
|
||||
if let Some(span) = span.span.span {
|
||||
Some(quote::quote_spanned!(span.into() => compile_error!{ #message }))
|
||||
} else {
|
||||
Some(quote!(compile_error! { #message }))
|
||||
}
|
||||
}
|
||||
// FIXME: find a way to report warnings.
|
||||
DiagnosticLevel::Warning => None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
quote!(#(#diags)*).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BuildDiagnostics {
|
||||
per_input_file_diagnostics: HashMap<PathBuf, FileDiagnostics>,
|
||||
internal_errors: Option<FileDiagnostics>,
|
||||
}
|
||||
|
||||
impl BuildDiagnostics {
|
||||
pub fn add(&mut self, diagnostics: FileDiagnostics) {
|
||||
match self.per_input_file_diagnostics.get_mut(&diagnostics.current_path.path) {
|
||||
Some(existing_diags) => existing_diags.inner.extend(diagnostics.inner),
|
||||
None => {
|
||||
self.per_input_file_diagnostics
|
||||
.insert(diagnostics.current_path.path.clone(), diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn file_diagnostics(&mut self, path: &Path) -> &mut FileDiagnostics {
|
||||
self.per_input_file_diagnostics.entry(path.into()).or_insert_with(|| FileDiagnostics {
|
||||
current_path: Rc::new(SourceFileInner { path: path.into(), ..Default::default() }),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push_diagnostic(
|
||||
&mut self,
|
||||
message: String,
|
||||
source: &dyn Spanned,
|
||||
level: DiagnosticLevel,
|
||||
) {
|
||||
match source.source_file() {
|
||||
Some(source_file) => self
|
||||
.file_diagnostics(source_file.path())
|
||||
.push_diagnostic_with_span(message, source.span(), level),
|
||||
None => self.push_internal_error(
|
||||
CompilerDiagnostic { message, span: source.to_source_location(), level }.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_error(&mut self, message: String, source: &dyn Spanned) {
|
||||
self.push_diagnostic(message, source, DiagnosticLevel::Error)
|
||||
self.push_diagnostic_with_span(message, source.to_source_location(), level)
|
||||
}
|
||||
|
||||
pub fn push_internal_error(&mut self, err: Diagnostic) {
|
||||
self.internal_errors
|
||||
.get_or_insert_with(|| FileDiagnostics {
|
||||
current_path: Rc::new(SourceFileInner {
|
||||
path: "[internal error]".into(),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
.inner
|
||||
.push(err)
|
||||
self.inner.push(err)
|
||||
}
|
||||
|
||||
pub fn push_property_deprecation_warning(
|
||||
&mut self,
|
||||
old_property: &str,
|
||||
new_property: &str,
|
||||
source: &impl Spanned,
|
||||
) {
|
||||
self.file_diagnostics(
|
||||
source.source_file().expect("deprecations cannot be created as internal errors").path(),
|
||||
)
|
||||
.push_property_deprecation_warning(old_property, new_property, source);
|
||||
}
|
||||
|
||||
fn iter(&self) -> impl Iterator<Item = &FileDiagnostics> {
|
||||
self.per_input_file_diagnostics.values().chain(self.internal_errors.iter())
|
||||
}
|
||||
|
||||
pub fn into_iter(self) -> impl Iterator<Item = FileDiagnostics> {
|
||||
self.per_input_file_diagnostics
|
||||
.into_iter()
|
||||
.map(|(_, diag)| diag)
|
||||
.chain(self.internal_errors.into_iter())
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
fn iter_mut(&mut self) -> impl Iterator<Item = &mut FileDiagnostics> {
|
||||
self.per_input_file_diagnostics.values_mut().chain(self.internal_errors.iter_mut())
|
||||
}
|
||||
|
||||
pub fn has_error(&self) -> bool {
|
||||
self.iter().any(|diag| diag.has_error())
|
||||
}
|
||||
|
||||
pub fn to_string_vec(&self) -> Vec<String> {
|
||||
self.iter()
|
||||
.flat_map(|diag| {
|
||||
diag.to_string_vec()
|
||||
.iter()
|
||||
.map(|err| format!("{}: {}", diag.current_path.path().to_string_lossy(), err))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
pub fn print(self) {
|
||||
self.into_iter().for_each(|diag| diag.print());
|
||||
}
|
||||
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
pub fn diagnostics_as_string(self) -> String {
|
||||
self.into_iter().map(|diag| diag.diagnostics_as_string()).collect::<Vec<_>>().join("\n")
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
|
@ -549,22 +435,4 @@ impl BuildDiagnostics {
|
|||
std::process::exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
pub fn map_offsets_to_span(&mut self, span_map: &[crate::parser::Token]) {
|
||||
self.iter_mut().for_each(|diag| diag.map_offsets_to_span(span_map))
|
||||
}
|
||||
|
||||
/// Return an iterator containing all the files
|
||||
pub fn files(&self) -> impl Iterator<Item = &'_ std::path::Path> + '_ {
|
||||
self.per_input_file_diagnostics.keys().map(|x| x.as_path())
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<FileDiagnostics> for BuildDiagnostics {
|
||||
fn extend<T: IntoIterator<Item = FileDiagnostics>>(&mut self, iter: T) {
|
||||
for diag in iter {
|
||||
self.add(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1022,7 +1022,7 @@ impl BindingExpression {
|
|||
pub fn new_uncompiled(node: SyntaxNodeWithSourceFile) -> Self {
|
||||
Self {
|
||||
expression: Expression::Uncompiled(node.clone()),
|
||||
span: Some(node.into()),
|
||||
span: Some(node.to_source_location()),
|
||||
priority: 0,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ mod cpp_ast {
|
|||
}
|
||||
}
|
||||
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, DiagnosticLevel, Spanned};
|
||||
use crate::diagnostics::{BuildDiagnostics, DiagnosticLevel, Spanned};
|
||||
use crate::expression_tree::{
|
||||
BindingExpression, BuiltinFunction, EasingCurve, Expression, NamedReference,
|
||||
};
|
||||
|
@ -263,7 +263,7 @@ impl CppType for Type {
|
|||
|
||||
fn get_cpp_type(ty: &Type, type_node: &dyn Spanned, diag: &mut BuildDiagnostics) -> String {
|
||||
ty.cpp_type().unwrap_or_else(|| {
|
||||
let err = CompilerDiagnostic {
|
||||
let err = crate::diagnostics::Diagnostic {
|
||||
message: "Cannot map property type to C++".into(),
|
||||
span: type_node.to_source_location(),
|
||||
level: DiagnosticLevel::Error,
|
||||
|
@ -1300,7 +1300,7 @@ fn model_data_type(parent_element: &ElementRc, diag: &mut BuildDiagnostics) -> S
|
|||
.ty();
|
||||
model_data_type.cpp_type().unwrap_or_else(|| {
|
||||
diag.push_internal_error(
|
||||
CompilerDiagnostic {
|
||||
crate::diagnostics::Diagnostic {
|
||||
message: format!("Cannot map property type {} to C++", model_data_type),
|
||||
span: parent_element
|
||||
.borrow()
|
||||
|
|
|
@ -13,7 +13,7 @@ Some convention used in the generated code:
|
|||
- `_self` is of type `Pin<&ComponentType>` where ComponentType is the type of the generated component
|
||||
*/
|
||||
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, DiagnosticLevel};
|
||||
use crate::diagnostics::{BuildDiagnostics, Diagnostic, DiagnosticLevel};
|
||||
use crate::expression_tree::{
|
||||
BuiltinFunction, EasingCurve, Expression, NamedReference, OperatorClass, Path,
|
||||
};
|
||||
|
@ -27,7 +27,7 @@ use std::{collections::BTreeMap, rc::Rc};
|
|||
fn rust_type(
|
||||
ty: &Type,
|
||||
span: Option<&dyn crate::diagnostics::Spanned>,
|
||||
) -> Result<proc_macro2::TokenStream, CompilerDiagnostic> {
|
||||
) -> Result<proc_macro2::TokenStream, Diagnostic> {
|
||||
match ty {
|
||||
Type::Int32 => Ok(quote!(i32)),
|
||||
Type::Float32 => Ok(quote!(f32)),
|
||||
|
@ -56,7 +56,7 @@ fn rust_type(
|
|||
Ok(quote!(sixtyfps::re_exports::#e))
|
||||
}
|
||||
Type::Brush => Ok(quote!(sixtyfps::Brush)),
|
||||
_ => Err(CompilerDiagnostic {
|
||||
_ => Err(Diagnostic {
|
||||
message: format!("Cannot map property type {} to Rust", ty),
|
||||
span: span.map(|s| s.to_source_location()).unwrap_or_default(),
|
||||
level: DiagnosticLevel::Error,
|
||||
|
|
|
@ -119,11 +119,9 @@ impl CompilerConfiguration {
|
|||
|
||||
pub async fn compile_syntax_node(
|
||||
doc_node: parser::SyntaxNodeWithSourceFile,
|
||||
mut diagnostics: diagnostics::FileDiagnostics,
|
||||
mut diagnostics: diagnostics::BuildDiagnostics,
|
||||
compiler_config: CompilerConfiguration,
|
||||
) -> (object_tree::Document, diagnostics::BuildDiagnostics) {
|
||||
let mut build_diagnostics = diagnostics::BuildDiagnostics::default();
|
||||
|
||||
let global_type_registry = typeregister::TypeRegister::builtin();
|
||||
let type_registry =
|
||||
Rc::new(RefCell::new(typeregister::TypeRegister::new(&global_type_registry)));
|
||||
|
@ -131,33 +129,26 @@ pub async fn compile_syntax_node(
|
|||
let doc_node: parser::syntax_nodes::Document = doc_node.into();
|
||||
|
||||
let mut loader =
|
||||
typeloader::TypeLoader::new(global_type_registry, &compiler_config, &mut build_diagnostics);
|
||||
typeloader::TypeLoader::new(global_type_registry, &compiler_config, &mut diagnostics);
|
||||
if doc_node.source_file.is_some() {
|
||||
loader
|
||||
.load_dependencies_recursively(
|
||||
&doc_node,
|
||||
&mut diagnostics,
|
||||
&mut build_diagnostics,
|
||||
&type_registry,
|
||||
)
|
||||
.await;
|
||||
loader.load_dependencies_recursively(&doc_node, &mut diagnostics, &type_registry).await;
|
||||
}
|
||||
|
||||
let doc = crate::object_tree::Document::from_node(doc_node, &mut diagnostics, &type_registry);
|
||||
|
||||
build_diagnostics.add(diagnostics);
|
||||
|
||||
if let Some((_, node)) = &*doc.root_component.child_insertion_point.borrow() {
|
||||
build_diagnostics
|
||||
diagnostics
|
||||
.push_error("@children placeholder not allowed in the final component".into(), node)
|
||||
}
|
||||
|
||||
if !build_diagnostics.has_error() {
|
||||
if !diagnostics.has_error() {
|
||||
// FIXME: ideally we would be able to run more passes, but currently we panic because invariant are not met.
|
||||
run_passes(&doc, &mut build_diagnostics, &mut loader, &compiler_config).await;
|
||||
run_passes(&doc, &mut diagnostics, &mut loader, &compiler_config).await;
|
||||
}
|
||||
|
||||
(doc, build_diagnostics)
|
||||
diagnostics.all_loaded_files = loader.all_files().cloned().collect();
|
||||
|
||||
(doc, diagnostics)
|
||||
}
|
||||
|
||||
pub async fn run_passes(
|
||||
|
|
|
@ -27,7 +27,8 @@ use crate::typeregister::TypeRegister;
|
|||
/// `register` is the register to fill with the builtin types.
|
||||
/// At this point, it really should already contain the basic Types (string, int, ...)
|
||||
pub fn load_builtins(register: &mut TypeRegister) {
|
||||
let (node, mut diag) = crate::parser::parse(include_str!("builtins.60").into(), None);
|
||||
let mut diag = crate::diagnostics::BuildDiagnostics::default();
|
||||
let node = crate::parser::parse(include_str!("builtins.60").into(), None, &mut diag);
|
||||
if !diag.is_empty() {
|
||||
let vec = diag.to_string_vec();
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
|
|
|
@ -11,7 +11,7 @@ LICENSE END */
|
|||
This module contains the intermediate representation of the code in the form of an object tree
|
||||
*/
|
||||
|
||||
use crate::diagnostics::{FileDiagnostics, Spanned};
|
||||
use crate::diagnostics::{BuildDiagnostics, Spanned};
|
||||
use crate::expression_tree::{self, Unit};
|
||||
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
|
||||
use crate::langtype::PropertyLookupResult;
|
||||
|
@ -36,7 +36,7 @@ pub struct Document {
|
|||
impl Document {
|
||||
pub fn from_node(
|
||||
node: syntax_nodes::Document,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
parent_registry: &Rc<RefCell<TypeRegister>>,
|
||||
) -> Self {
|
||||
debug_assert_eq!(node.kind(), SyntaxKind::Document);
|
||||
|
@ -47,7 +47,7 @@ impl Document {
|
|||
|
||||
let mut process_component =
|
||||
|n: syntax_nodes::Component,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
local_registry: &mut TypeRegister| {
|
||||
let compo = Component::from_node(n, diag, local_registry);
|
||||
local_registry.add(compo.clone());
|
||||
|
@ -55,7 +55,7 @@ impl Document {
|
|||
};
|
||||
let mut process_struct =
|
||||
|n: syntax_nodes::StructDeclaration,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
local_registry: &mut TypeRegister| {
|
||||
let mut ty = type_struct_from_node(n.ObjectType(), diag, local_registry);
|
||||
if let Type::Object { name, .. } = &mut ty {
|
||||
|
@ -172,7 +172,7 @@ pub struct Component {
|
|||
impl Component {
|
||||
pub fn from_node(
|
||||
node: syntax_nodes::Component,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> Rc<Self> {
|
||||
let mut child_insertion_point = None;
|
||||
|
@ -373,7 +373,7 @@ impl Element {
|
|||
id: String,
|
||||
parent_type: Type,
|
||||
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> ElementRc {
|
||||
let (base_type, name_for_looup_errors) = if let Some(base_node) = node.QualifiedName() {
|
||||
|
@ -711,7 +711,7 @@ impl Element {
|
|||
node: syntax_nodes::RepeatedElement,
|
||||
parent: &ElementRc,
|
||||
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> ElementRc {
|
||||
let is_listview = if parent.borrow().base_type.to_string() == "ListView" {
|
||||
|
@ -751,7 +751,7 @@ impl Element {
|
|||
node: syntax_nodes::ConditionalElement,
|
||||
parent_type: Type,
|
||||
component_child_insertion_point: &mut Option<ChildrenInsertionPoint>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> ElementRc {
|
||||
let rei = RepeatedElementInfo {
|
||||
|
@ -794,7 +794,7 @@ impl Element {
|
|||
bindings: impl Iterator<
|
||||
Item = (crate::parser::SyntaxTokenWithSourceFile, SyntaxNodeWithSourceFile),
|
||||
>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
for (name_token, b) in bindings {
|
||||
let unresolved_name = crate::parser::normalize_identifier(name_token.text());
|
||||
|
@ -854,7 +854,7 @@ impl Element {
|
|||
/// Create a Type for this node
|
||||
pub fn type_from_node(
|
||||
node: syntax_nodes::Type,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> Type {
|
||||
if let Some(qualified_type_node) = node.QualifiedName() {
|
||||
|
@ -882,7 +882,7 @@ pub fn type_from_node(
|
|||
/// Create a Type::Object from a syntax_nodes::ObjectType
|
||||
pub fn type_struct_from_node(
|
||||
object_node: syntax_nodes::ObjectType,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> Type {
|
||||
let fields = object_node
|
||||
|
@ -898,7 +898,7 @@ fn animation_element_from_node(
|
|||
anim: &syntax_nodes::PropertyAnimation,
|
||||
prop_name: &syntax_nodes::QualifiedName,
|
||||
prop_type: Type,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
tr: &TypeRegister,
|
||||
) -> Option<ElementRc> {
|
||||
let anim_type = tr.property_animation_type_for_property(prop_type);
|
||||
|
@ -951,7 +951,7 @@ impl std::fmt::Display for QualifiedTypeName {
|
|||
fn lookup_property_from_qualified_name(
|
||||
node: syntax_nodes::QualifiedName,
|
||||
r: &Rc<RefCell<Element>>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) -> (NamedReference, Type) {
|
||||
let qualname = QualifiedTypeName::from_node(node.clone());
|
||||
match qualname.members.as_slice() {
|
||||
|
@ -1261,7 +1261,7 @@ impl Exports {
|
|||
doc: &syntax_nodes::Document,
|
||||
inner_components: &[Rc<Component>],
|
||||
type_registry: &TypeRegister,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) -> Self {
|
||||
#[derive(Debug, Clone)]
|
||||
struct NamedExport {
|
||||
|
|
|
@ -18,7 +18,7 @@ This module has different sub modules with the actual parser functions
|
|||
|
||||
*/
|
||||
|
||||
use crate::diagnostics::{FileDiagnostics, SourceFile, Spanned};
|
||||
use crate::diagnostics::{BuildDiagnostics, SourceFile, Spanned};
|
||||
pub use smol_str::SmolStr;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
@ -506,23 +506,28 @@ mod parser_trait {
|
|||
#[doc(inline)]
|
||||
pub use parser_trait::*;
|
||||
|
||||
pub struct DefaultParser {
|
||||
pub struct DefaultParser<'a> {
|
||||
builder: rowan::GreenNodeBuilder<'static>,
|
||||
tokens: Vec<Token>,
|
||||
cursor: usize,
|
||||
diags: FileDiagnostics,
|
||||
diags: &'a mut BuildDiagnostics,
|
||||
source_file: SourceFile,
|
||||
}
|
||||
|
||||
impl From<Vec<Token>> for DefaultParser {
|
||||
fn from(tokens: Vec<Token>) -> Self {
|
||||
Self { builder: Default::default(), tokens, cursor: 0, diags: Default::default() }
|
||||
impl<'a> DefaultParser<'a> {
|
||||
fn from_tokens(tokens: Vec<Token>, diags: &'a mut BuildDiagnostics) -> Self {
|
||||
Self {
|
||||
builder: Default::default(),
|
||||
tokens,
|
||||
cursor: 0,
|
||||
diags,
|
||||
source_file: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefaultParser {
|
||||
/// Constructor that create a parser from the source code
|
||||
pub fn new(source: &str) -> Self {
|
||||
Self::from(crate::lexer::lex(&source))
|
||||
pub fn new(source: &str, diags: &'a mut BuildDiagnostics) -> Self {
|
||||
Self::from_tokens(crate::lexer::lex(&source), diags)
|
||||
}
|
||||
|
||||
fn current_token(&self) -> Token {
|
||||
|
@ -537,7 +542,7 @@ impl DefaultParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl Parser for DefaultParser {
|
||||
impl Parser for DefaultParser<'_> {
|
||||
fn start_node_impl(
|
||||
&mut self,
|
||||
kind: SyntaxKind,
|
||||
|
@ -586,7 +591,14 @@ impl Parser for DefaultParser {
|
|||
{
|
||||
span.span = current_token.span;
|
||||
}
|
||||
self.diags.push_error_with_span(e.into(), span);
|
||||
|
||||
self.diags.push_error_with_span(
|
||||
e.into(),
|
||||
crate::diagnostics::SourceLocation {
|
||||
source_file: Some(self.source_file.clone()),
|
||||
span,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
type Checkpoint = rowan::Checkpoint;
|
||||
|
@ -808,33 +820,30 @@ pub fn normalize_identifier(ident: &str) -> String {
|
|||
pub fn parse(
|
||||
source: String,
|
||||
path: Option<&std::path::Path>,
|
||||
) -> (SyntaxNodeWithSourceFile, FileDiagnostics) {
|
||||
let mut p = DefaultParser::new(&source);
|
||||
document::parse_document(&mut p);
|
||||
build_diagnostics: &mut BuildDiagnostics,
|
||||
) -> SyntaxNodeWithSourceFile {
|
||||
let mut p = DefaultParser::new(&source, build_diagnostics);
|
||||
let source_file = if let Some(path) = path {
|
||||
p.diags.current_path =
|
||||
p.source_file =
|
||||
std::rc::Rc::new(crate::diagnostics::SourceFileInner::new(path.to_path_buf(), source));
|
||||
Some(p.diags.current_path.clone())
|
||||
Some(p.source_file.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
(
|
||||
SyntaxNodeWithSourceFile { node: SyntaxNode::new_root(p.builder.finish()), source_file },
|
||||
p.diags,
|
||||
)
|
||||
document::parse_document(&mut p);
|
||||
SyntaxNodeWithSourceFile { node: SyntaxNode::new_root(p.builder.finish()), source_file }
|
||||
}
|
||||
|
||||
pub fn parse_file<P: AsRef<std::path::Path>>(
|
||||
path: P,
|
||||
) -> std::io::Result<(SyntaxNodeWithSourceFile, FileDiagnostics)> {
|
||||
build_diagnostics: &mut BuildDiagnostics,
|
||||
) -> std::io::Result<SyntaxNodeWithSourceFile> {
|
||||
let source = std::fs::read_to_string(&path)?;
|
||||
|
||||
Ok(parse(source, Some(path.as_ref())))
|
||||
Ok(parse(source, Some(path.as_ref()), build_diagnostics))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn parse_tokens(tokens: Vec<Token>) -> (SyntaxNode, FileDiagnostics) {
|
||||
let mut p = DefaultParser::from(tokens);
|
||||
pub fn parse_tokens(tokens: Vec<Token>, diags: &mut BuildDiagnostics) -> SyntaxNode {
|
||||
let mut p = DefaultParser::from_tokens(tokens, diags);
|
||||
document::parse_document(&mut p);
|
||||
(SyntaxNode::new_root(p.builder.finish()), p.diags)
|
||||
SyntaxNode::new_root(p.builder.finish())
|
||||
}
|
||||
|
|
|
@ -26,15 +26,9 @@ pub async fn apply_default_properties_from_style<'a>(
|
|||
_diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
// Ignore import errors
|
||||
let mut file_diags_to_ignore = crate::diagnostics::FileDiagnostics::default();
|
||||
let mut build_diags_to_ignore = BuildDiagnostics::default();
|
||||
let style_metrics = type_loader
|
||||
.import_type(
|
||||
"sixtyfps_widgets.60",
|
||||
"StyleMetrics",
|
||||
&mut file_diags_to_ignore,
|
||||
&mut build_diags_to_ignore,
|
||||
)
|
||||
.import_type("sixtyfps_widgets.60", "StyleMetrics", &mut build_diags_to_ignore)
|
||||
.await;
|
||||
let style_metrics = if let Some(Type::Component(c)) = style_metrics { c } else { return };
|
||||
|
||||
|
|
|
@ -246,15 +246,9 @@ pub async fn lower_layouts<'a>(
|
|||
diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
// Ignore import errors
|
||||
let mut file_diags_to_ignore = crate::diagnostics::FileDiagnostics::default();
|
||||
let mut build_diags_to_ignore = crate::diagnostics::BuildDiagnostics::default();
|
||||
let style_metrics = type_loader
|
||||
.import_type(
|
||||
"sixtyfps_widgets.60",
|
||||
"StyleMetrics",
|
||||
&mut file_diags_to_ignore,
|
||||
&mut build_diags_to_ignore,
|
||||
)
|
||||
.import_type("sixtyfps_widgets.60", "StyleMetrics", &mut build_diags_to_ignore)
|
||||
.await;
|
||||
let style_metrics =
|
||||
style_metrics.and_then(|sm| if let Type::Component(c) = sm { Some(c) } else { None });
|
||||
|
|
|
@ -15,6 +15,8 @@ LICENSE END */
|
|||
//! // ^error{some_regexp}
|
||||
//! ```
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[test]
|
||||
fn syntax_tests() -> std::io::Result<()> {
|
||||
if let Some(specific_test) = std::env::args()
|
||||
|
@ -57,12 +59,17 @@ fn process_file(path: &std::path::Path) -> std::io::Result<bool> {
|
|||
}
|
||||
|
||||
fn process_diagnostics(
|
||||
mut compile_diagnostics: sixtyfps_compilerlib::diagnostics::FileDiagnostics,
|
||||
source: String,
|
||||
compile_diagnostics: &sixtyfps_compilerlib::diagnostics::BuildDiagnostics,
|
||||
path: &Path,
|
||||
source: &str,
|
||||
silent: bool,
|
||||
) -> std::io::Result<bool> {
|
||||
let mut success = true;
|
||||
let path = compile_diagnostics.current_path.as_ref();
|
||||
|
||||
let mut diags = compile_diagnostics
|
||||
.iter()
|
||||
.filter(|d| &cannonical(d.span.source_file.as_ref().unwrap().path()) == path)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Find expected errors in the file. The first caret (^) points to the expected column. The number of
|
||||
// carets refers to the number of lines to go back. This is useful when one line of code produces multiple
|
||||
|
@ -98,14 +105,11 @@ fn process_diagnostics(
|
|||
_ => panic!("Unsupported diagnostic level {}", warning_or_error),
|
||||
};
|
||||
|
||||
match compile_diagnostics.inner.iter().position(|e| match e {
|
||||
sixtyfps_compilerlib::diagnostics::Diagnostic::FileLoadError(_) => false,
|
||||
sixtyfps_compilerlib::diagnostics::Diagnostic::CompilerDiagnostic(e) => {
|
||||
e.span.offset == offset && r.is_match(&e.message) && e.level == expected_diag_level
|
||||
}
|
||||
match diags.iter().position(|e| {
|
||||
e.span.span.offset == offset && r.is_match(&e.message) && e.level == expected_diag_level
|
||||
}) {
|
||||
Some(idx) => {
|
||||
compile_diagnostics.inner.remove(idx);
|
||||
diags.remove(idx);
|
||||
}
|
||||
None => {
|
||||
success = false;
|
||||
|
@ -116,28 +120,35 @@ fn process_diagnostics(
|
|||
}
|
||||
}
|
||||
}
|
||||
if !diags.is_empty() {
|
||||
println!("{:?}: Unexptected errors/warnings: {:#?}", path, diags);
|
||||
|
||||
if !compile_diagnostics.inner.is_empty() {
|
||||
println!("{:?}: Unexptected errors/warnings: {:#?}", path, compile_diagnostics.inner);
|
||||
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
if !silent {
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
compile_diagnostics.print();
|
||||
let mut to_report = sixtyfps_compilerlib::diagnostics::BuildDiagnostics::default();
|
||||
for d in diags {
|
||||
to_report.push_compiler_error(d.clone());
|
||||
}
|
||||
to_report.print();
|
||||
}
|
||||
|
||||
success = false;
|
||||
}
|
||||
|
||||
Ok(success)
|
||||
}
|
||||
|
||||
fn cannonical(path: &Path) -> PathBuf {
|
||||
path.canonicalize().unwrap_or_else(|_| path.to_owned())
|
||||
}
|
||||
|
||||
fn process_file_source(
|
||||
path: &std::path::Path,
|
||||
source: String,
|
||||
silent: bool,
|
||||
) -> std::io::Result<bool> {
|
||||
let (syntax_node, parse_diagnostics) =
|
||||
sixtyfps_compilerlib::parser::parse(source.clone(), Some(path));
|
||||
let mut parse_diagnostics = sixtyfps_compilerlib::diagnostics::BuildDiagnostics::default();
|
||||
let syntax_node =
|
||||
sixtyfps_compilerlib::parser::parse(source.clone(), Some(path), &mut parse_diagnostics);
|
||||
let compile_diagnostics = if !parse_diagnostics.has_error() {
|
||||
let mut compiler_config = sixtyfps_compilerlib::CompilerConfiguration::new(
|
||||
sixtyfps_compilerlib::generator::OutputFormat::Interpreter,
|
||||
|
@ -148,22 +159,22 @@ fn process_file_source(
|
|||
parse_diagnostics,
|
||||
compiler_config,
|
||||
));
|
||||
build_diags.into_iter().collect()
|
||||
build_diags
|
||||
} else {
|
||||
vec![parse_diagnostics]
|
||||
parse_diagnostics
|
||||
};
|
||||
|
||||
assert!(compile_diagnostics.len() >= 1);
|
||||
|
||||
let mut success = true;
|
||||
success &= process_diagnostics(&compile_diagnostics, &path, &source, silent)?;
|
||||
|
||||
for diagnostics in compile_diagnostics.into_iter() {
|
||||
let source = if diagnostics.current_path.path() == path {
|
||||
source.clone()
|
||||
for p in &compile_diagnostics.all_loaded_files {
|
||||
let source = if p.is_absolute() {
|
||||
std::fs::read_to_string(&p)?
|
||||
} else {
|
||||
std::fs::read_to_string(diagnostics.current_path.path())?
|
||||
// probably sixtyfps_widgets.60
|
||||
String::new()
|
||||
};
|
||||
success &= process_diagnostics(diagnostics, source, silent)?;
|
||||
success &= process_diagnostics(&compile_diagnostics, &p, &source, silent)?;
|
||||
}
|
||||
|
||||
Ok(success)
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::io::Read;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, FileDiagnostics};
|
||||
use crate::diagnostics::{BuildDiagnostics, Diagnostic};
|
||||
use crate::object_tree::{self, Document};
|
||||
use crate::parser::{syntax_nodes, SyntaxKind, SyntaxTokenWithSourceFile};
|
||||
use crate::typeregister::TypeRegister;
|
||||
|
@ -131,7 +131,7 @@ impl<'a> TypeLoader<'a> {
|
|||
let is_wasm = cfg!(target_arch = "wasm32")
|
||||
|| std::env::var("TARGET").map_or(false, |t| t.starts_with("wasm"));
|
||||
if !is_wasm {
|
||||
diag.push_internal_error(CompilerDiagnostic {
|
||||
diag.push_internal_error(Diagnostic {
|
||||
message: "SIXTYFPS_STYLE not defined, defaulting to 'ugly', see https://github.com/sixtyfpsui/sixtyfps/issues/83 for more info".to_owned(),
|
||||
span: Default::default(),
|
||||
level: crate::diagnostics::DiagnosticLevel::Warning
|
||||
|
@ -154,14 +154,12 @@ impl<'a> TypeLoader<'a> {
|
|||
pub async fn load_dependencies_recursively(
|
||||
&mut self,
|
||||
doc: &syntax_nodes::Document,
|
||||
mut diagnostics: &mut FileDiagnostics,
|
||||
build_diagnostics: &mut BuildDiagnostics,
|
||||
diagnostics: &mut BuildDiagnostics,
|
||||
registry_to_populate: &Rc<RefCell<TypeRegister>>,
|
||||
) {
|
||||
let dependencies = self.collect_dependencies(&doc, &mut diagnostics).await;
|
||||
let dependencies = self.collect_dependencies(&doc, diagnostics).await;
|
||||
for import in dependencies.into_iter() {
|
||||
self.load_dependency(import, registry_to_populate, diagnostics, build_diagnostics)
|
||||
.await;
|
||||
self.load_dependency(import, registry_to_populate, diagnostics).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,8 +167,7 @@ impl<'a> TypeLoader<'a> {
|
|||
&mut self,
|
||||
file_to_import: &str,
|
||||
type_name: &str,
|
||||
diagnostics: &mut FileDiagnostics,
|
||||
build_diagnostics: &mut BuildDiagnostics,
|
||||
diagnostics: &mut BuildDiagnostics,
|
||||
) -> Option<crate::langtype::Type> {
|
||||
let file = match self.import_file(None, file_to_import) {
|
||||
Some(file) => file,
|
||||
|
@ -178,13 +175,7 @@ impl<'a> TypeLoader<'a> {
|
|||
};
|
||||
|
||||
let doc_path = match self
|
||||
.ensure_document_loaded(
|
||||
&file.path,
|
||||
file.source_code_future,
|
||||
None,
|
||||
Some(diagnostics),
|
||||
build_diagnostics,
|
||||
)
|
||||
.ensure_document_loaded(&file.path, file.source_code_future, None, diagnostics)
|
||||
.await
|
||||
{
|
||||
Some(doc_path) => doc_path,
|
||||
|
@ -207,8 +198,7 @@ impl<'a> TypeLoader<'a> {
|
|||
path: &'b Path,
|
||||
source_code_future: impl std::future::Future<Output = std::io::Result<String>>,
|
||||
import_token: Option<SyntaxTokenWithSourceFile>,
|
||||
importer_diagnostics: Option<&'b mut FileDiagnostics>,
|
||||
build_diagnostics: &'b mut BuildDiagnostics,
|
||||
diagnostics: &'b mut BuildDiagnostics,
|
||||
) -> Option<PathBuf> {
|
||||
let path_canon = path.canonicalize().unwrap_or_else(|_| path.to_owned());
|
||||
|
||||
|
@ -217,8 +207,7 @@ impl<'a> TypeLoader<'a> {
|
|||
}
|
||||
|
||||
if !self.all_documents.currently_loading.insert(path_canon.clone()) {
|
||||
importer_diagnostics
|
||||
.unwrap()
|
||||
diagnostics
|
||||
.push_error(format!("Recursive import of {}", path.display()), &import_token);
|
||||
return None;
|
||||
}
|
||||
|
@ -226,7 +215,7 @@ impl<'a> TypeLoader<'a> {
|
|||
let source_code = match source_code_future.await {
|
||||
Ok(source) => source,
|
||||
Err(err) => {
|
||||
importer_diagnostics.unwrap().push_error(
|
||||
diagnostics.push_error(
|
||||
format!("Error reading requested import {}: {}", path.display(), err),
|
||||
&import_token,
|
||||
);
|
||||
|
@ -234,7 +223,7 @@ impl<'a> TypeLoader<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
self.load_file(&path_canon, path, source_code, build_diagnostics).await;
|
||||
self.load_file(&path_canon, path, source_code, diagnostics).await;
|
||||
let _ok = self.all_documents.currently_loading.remove(path_canon.as_path());
|
||||
assert!(_ok);
|
||||
Some(path_canon)
|
||||
|
@ -248,13 +237,11 @@ impl<'a> TypeLoader<'a> {
|
|||
path: &Path,
|
||||
source_path: &Path,
|
||||
source_code: String,
|
||||
build_diagnostics: &mut BuildDiagnostics,
|
||||
diagnostics: &mut BuildDiagnostics,
|
||||
) {
|
||||
let (dependency_doc, mut dependency_diagnostics) =
|
||||
crate::parser::parse(source_code, Some(&source_path));
|
||||
let dependency_doc = crate::parser::parse(source_code, Some(&source_path), diagnostics);
|
||||
|
||||
if dependency_diagnostics.has_error() {
|
||||
build_diagnostics.add(dependency_diagnostics);
|
||||
if diagnostics.has_error() {
|
||||
let mut d = Document::default();
|
||||
d.node = Some(dependency_doc.into());
|
||||
self.all_documents.docs.insert(path.to_owned(), d);
|
||||
|
@ -265,25 +252,15 @@ impl<'a> TypeLoader<'a> {
|
|||
|
||||
let dependency_registry =
|
||||
Rc::new(RefCell::new(TypeRegister::new(&self.global_type_registry)));
|
||||
self.load_dependencies_recursively(
|
||||
&dependency_doc,
|
||||
&mut dependency_diagnostics,
|
||||
build_diagnostics,
|
||||
&dependency_registry,
|
||||
)
|
||||
.await;
|
||||
self.load_dependencies_recursively(&dependency_doc, diagnostics, &dependency_registry)
|
||||
.await;
|
||||
|
||||
let doc = crate::object_tree::Document::from_node(
|
||||
dependency_doc,
|
||||
&mut dependency_diagnostics,
|
||||
diagnostics,
|
||||
&dependency_registry,
|
||||
);
|
||||
crate::passes::resolving::resolve_expressions(&doc, &self, build_diagnostics);
|
||||
|
||||
// Add diagnostics regardless whether they're empty or not. This is used by the syntax_tests to
|
||||
// also verify that imported files have no errors.
|
||||
build_diagnostics.add(dependency_diagnostics);
|
||||
|
||||
crate::passes::resolving::resolve_expressions(&doc, &self, diagnostics);
|
||||
self.all_documents.docs.insert(path.to_owned(), doc);
|
||||
}
|
||||
|
||||
|
@ -291,7 +268,6 @@ impl<'a> TypeLoader<'a> {
|
|||
&'b mut self,
|
||||
import: ImportedTypes,
|
||||
registry_to_populate: &'b Rc<RefCell<TypeRegister>>,
|
||||
importer_diagnostics: &'b mut FileDiagnostics,
|
||||
build_diagnostics: &'b mut BuildDiagnostics,
|
||||
) -> core::pin::Pin<Box<dyn std::future::Future<Output = ()> + 'b>> {
|
||||
Box::pin(async move {
|
||||
|
@ -300,7 +276,6 @@ impl<'a> TypeLoader<'a> {
|
|||
&import.file.path,
|
||||
import.file.source_code_future,
|
||||
Some(import.import_token.clone()),
|
||||
Some(importer_diagnostics),
|
||||
build_diagnostics,
|
||||
)
|
||||
.await
|
||||
|
@ -324,7 +299,7 @@ impl<'a> TypeLoader<'a> {
|
|||
let imported_type = match imported_type {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
importer_diagnostics.push_error(
|
||||
build_diagnostics.push_error(
|
||||
format!(
|
||||
"No exported type called {} found in {}",
|
||||
import_name.external_name,
|
||||
|
@ -391,7 +366,7 @@ impl<'a> TypeLoader<'a> {
|
|||
async fn collect_dependencies(
|
||||
&mut self,
|
||||
doc: &syntax_nodes::Document,
|
||||
doc_diagnostics: &mut FileDiagnostics,
|
||||
doc_diagnostics: &mut BuildDiagnostics,
|
||||
) -> impl Iterator<Item = ImportedTypes> {
|
||||
let referencing_file = doc.source_file.as_ref().unwrap().path().clone();
|
||||
|
||||
|
@ -445,6 +420,11 @@ impl<'a> TypeLoader<'a> {
|
|||
|path| self.all_documents.docs.get(&path),
|
||||
)
|
||||
}
|
||||
|
||||
/// Return an iterator over all the loaded file path
|
||||
pub fn all_files<'b>(&'b self) -> impl Iterator<Item = &PathBuf> + 'b {
|
||||
self.all_documents.docs.keys()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -535,7 +515,6 @@ fn test_manual_import() {
|
|||
let mut compiler_config =
|
||||
CompilerConfiguration::new(crate::generator::OutputFormat::Interpreter);
|
||||
compiler_config.style = Some("ugly".into());
|
||||
let mut test_diags = FileDiagnostics::default();
|
||||
let global_registry = TypeRegister::builtin();
|
||||
let mut build_diagnostics = BuildDiagnostics::default();
|
||||
let mut loader = TypeLoader::new(global_registry, &compiler_config, &mut build_diagnostics);
|
||||
|
@ -543,11 +522,9 @@ fn test_manual_import() {
|
|||
let maybe_button_type = spin_on::spin_on(loader.import_type(
|
||||
"sixtyfps_widgets.60",
|
||||
"Button",
|
||||
&mut test_diags,
|
||||
&mut build_diagnostics,
|
||||
));
|
||||
|
||||
assert!(!test_diags.has_error());
|
||||
assert!(!build_diagnostics.has_error());
|
||||
assert!(maybe_button_type.is_some());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use core::ptr::NonNull;
|
|||
use dynamic_type::{Instance, InstanceBox};
|
||||
use expression_tree::NamedReference;
|
||||
use object_tree::{Element, ElementRc};
|
||||
use sixtyfps_compilerlib::diagnostics::BuildDiagnostics;
|
||||
use sixtyfps_compilerlib::langtype::Type;
|
||||
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem, PathLayout};
|
||||
use sixtyfps_compilerlib::*;
|
||||
|
@ -620,11 +621,10 @@ pub async fn load<'id>(
|
|||
guard: generativity::Guard<'id>,
|
||||
) -> (Result<Rc<ComponentDescription<'id>>, ()>, sixtyfps_compilerlib::diagnostics::BuildDiagnostics)
|
||||
{
|
||||
let (syntax_node, diag) = parser::parse(source, Some(path.as_path()));
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = parser::parse(source, Some(path.as_path()), &mut diag);
|
||||
if diag.has_error() {
|
||||
let mut d = sixtyfps_compilerlib::diagnostics::BuildDiagnostics::default();
|
||||
d.add(diag);
|
||||
return (Err(()), d);
|
||||
return (Err(()), diag);
|
||||
}
|
||||
let (doc, diag) = compile_syntax_node(syntax_node, diag, compiler_config).await;
|
||||
if diag.has_error() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
This file is also available under commercial licensing terms.
|
||||
Please contact info@sixtyfps.io for more information.
|
||||
LICENSE END */
|
||||
use sixtyfps_compilerlib::diagnostics::BuildDiagnostics;
|
||||
use sixtyfps_compilerlib::*;
|
||||
use std::io::Write;
|
||||
use structopt::StructOpt;
|
||||
|
@ -41,7 +42,8 @@ struct Cli {
|
|||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let args = Cli::from_args();
|
||||
let (syntax_node, diag) = parser::parse_file(&args.path)?;
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = parser::parse_file(&args.path, &mut diag)?;
|
||||
//println!("{:#?}", syntax_node);
|
||||
if diag.has_error() {
|
||||
diag.print();
|
||||
|
@ -67,7 +69,7 @@ fn main() -> std::io::Result<()> {
|
|||
if let Some(depfile) = args.depfile {
|
||||
let mut f = std::fs::File::create(depfile)?;
|
||||
write!(f, "{}:", args.output.display())?;
|
||||
for x in diag.files() {
|
||||
for x in &diag.all_loaded_files {
|
||||
if x.is_absolute() {
|
||||
write!(f, " {}", x.display())?;
|
||||
}
|
||||
|
|
|
@ -196,18 +196,20 @@ fn reload_document(
|
|||
let mut diag = BuildDiagnostics::default();
|
||||
spin_on::spin_on(document_cache.documents.load_file(&path_canon, path, content, &mut diag));
|
||||
|
||||
for file_diag in diag.into_iter() {
|
||||
if file_diag.current_path.path().is_relative() {
|
||||
let mut lsp_diags = HashMap::<Url, Vec<lsp_types::Diagnostic>>::new();
|
||||
|
||||
for d in diag.into_iter() {
|
||||
if d.span.source_file.as_ref().unwrap().path().is_relative() {
|
||||
continue;
|
||||
}
|
||||
let diagnostics = file_diag.inner.iter().map(|d| to_lsp_diag(d)).collect();
|
||||
let uri = Url::from_file_path(d.span.source_file.as_ref().unwrap().path()).unwrap();
|
||||
lsp_diags.entry(uri).or_default().push(to_lsp_diag(&d));
|
||||
}
|
||||
|
||||
for (uri, diagnostics) in lsp_diags {
|
||||
connection.sender.send(Message::Notification(lsp_server::Notification::new(
|
||||
"textDocument/publishDiagnostics".into(),
|
||||
PublishDiagnosticsParams {
|
||||
uri: Url::from_file_path(file_diag.current_path.path()).unwrap(),
|
||||
diagnostics,
|
||||
version: None,
|
||||
},
|
||||
PublishDiagnosticsParams { uri, diagnostics, version: None },
|
||||
)))?;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ LICENSE END */
|
|||
//! cargo run --bin syntax_updater -- -i **/*.md
|
||||
//! ````
|
||||
|
||||
use sixtyfps_compilerlib::diagnostics::BuildDiagnostics;
|
||||
use sixtyfps_compilerlib::parser::{SyntaxKind, SyntaxNode, SyntaxNodeEx};
|
||||
use std::io::Write;
|
||||
use structopt::StructOpt;
|
||||
|
@ -92,7 +93,8 @@ fn process_rust_file(source: String, mut file: impl Write) -> std::io::Result<()
|
|||
let code = &source_slice[..idx - 1];
|
||||
source_slice = &source_slice[idx - 1..];
|
||||
|
||||
let (syntax_node, diag) = sixtyfps_compilerlib::parser::parse(code.to_owned(), None);
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = sixtyfps_compilerlib::parser::parse(code.to_owned(), None, &mut diag);
|
||||
let len = syntax_node.node.text_range().end().into();
|
||||
visit_node(syntax_node.node, &mut file, &mut State::default())?;
|
||||
if diag.has_error() {
|
||||
|
@ -120,7 +122,8 @@ fn process_markdown_file(source: String, mut file: impl Write) -> std::io::Resul
|
|||
let code = &source_slice[..code_end];
|
||||
source_slice = &source_slice[code_end..];
|
||||
|
||||
let (syntax_node, diag) = sixtyfps_compilerlib::parser::parse(code.to_owned(), None);
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = sixtyfps_compilerlib::parser::parse(code.to_owned(), None, &mut diag);
|
||||
let len = syntax_node.node.text_range().end().into();
|
||||
visit_node(syntax_node.node, &mut file, &mut State::default())?;
|
||||
if diag.has_error() {
|
||||
|
@ -142,7 +145,8 @@ fn process_file(
|
|||
_ => {}
|
||||
}
|
||||
|
||||
let (syntax_node, diag) = sixtyfps_compilerlib::parser::parse(source.clone(), Some(&path));
|
||||
let mut diag = BuildDiagnostics::default();
|
||||
let syntax_node = sixtyfps_compilerlib::parser::parse(source.clone(), Some(&path), &mut diag);
|
||||
let len = syntax_node.node.text_range().end().into();
|
||||
visit_node(syntax_node.node, &mut file, &mut State::default())?;
|
||||
if diag.has_error() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue