Skip to content

Commit

Permalink
Add embed declaration for foreign language integration
Browse files Browse the repository at this point in the history
  • Loading branch information
dalance committed Apr 10, 2024
1 parent 960f29c commit 71b4904
Show file tree
Hide file tree
Showing 19 changed files with 16,121 additions and 15,011 deletions.
50 changes: 50 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,40 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unknown_embed_lang),
help(""),
url(
"https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#unknown_embed_lang"
)
)]
#[error("\"{name}\" is not valid embed language")]
UnknownEmbedLang {
name: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unknown_embed_way),
help(""),
url(
"https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#unknown_embed_way"
)
)]
#[error("\"{name}\" is not valid embed way")]
UnknownEmbedWay {
name: String,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unknown_member),
Expand Down Expand Up @@ -777,6 +811,22 @@ impl AnalyzerError {
}
}

pub fn unknown_embed_lang(name: &str, source: &str, token: &Token) -> Self {
AnalyzerError::UnknownEmbedLang {
name: name.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn unknown_embed_way(name: &str, source: &str, token: &Token) -> Self {
AnalyzerError::UnknownEmbedWay {
name: name.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn unknown_member(name: &str, member: &str, source: &str, token: &Token) -> Self {
AnalyzerError::UnknownMember {
name: name.to_string(),
Expand Down
6 changes: 6 additions & 0 deletions crates/analyzer/src/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod check_assignment;
pub mod check_attribute;
pub mod check_direction;
pub mod check_embed;
pub mod check_enum;
pub mod check_function;
pub mod check_identifier;
Expand All @@ -14,6 +15,7 @@ pub mod create_symbol_table;
pub mod create_type_dag;
use check_attribute::*;
use check_direction::*;
use check_embed::*;
use check_enum::*;
use check_function::*;
use check_identifier::*;
Expand All @@ -34,6 +36,7 @@ use self::{check_assignment::CheckAssignment, create_type_dag::CreateTypeDag};
pub struct Pass1Handlers<'a> {
check_attribute: CheckAttribute<'a>,
check_direction: CheckDirection<'a>,
check_embed: CheckEmbed<'a>,
check_identifier: CheckIdentifier<'a>,
check_number: CheckNumber<'a>,
check_reset: CheckReset<'a>,
Expand All @@ -46,6 +49,7 @@ impl<'a> Pass1Handlers<'a> {
Self {
check_attribute: CheckAttribute::new(text),
check_direction: CheckDirection::new(text),
check_embed: CheckEmbed::new(text),
check_identifier: CheckIdentifier::new(text, lint_opt),
check_number: CheckNumber::new(text),
check_reset: CheckReset::new(text),
Expand All @@ -58,6 +62,7 @@ impl<'a> Pass1Handlers<'a> {
vec![
&mut self.check_attribute as &mut dyn Handler,
&mut self.check_direction as &mut dyn Handler,
&mut self.check_embed as &mut dyn Handler,
&mut self.check_identifier as &mut dyn Handler,
&mut self.check_number as &mut dyn Handler,
&mut self.check_reset as &mut dyn Handler,
Expand All @@ -70,6 +75,7 @@ impl<'a> Pass1Handlers<'a> {
let mut ret = Vec::new();
ret.append(&mut self.check_attribute.errors);
ret.append(&mut self.check_direction.errors);
ret.append(&mut self.check_embed.errors);
ret.append(&mut self.check_identifier.errors);
ret.append(&mut self.check_number.errors);
ret.append(&mut self.check_reset.errors);
Expand Down
55 changes: 55 additions & 0 deletions crates/analyzer/src/handlers/check_embed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::analyzer_error::AnalyzerError;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;

pub struct CheckEmbed<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
point: HandlerPoint,
}

impl<'a> CheckEmbed<'a> {
pub fn new(text: &'a str) -> Self {
Self {
errors: Vec::new(),
text,
point: HandlerPoint::Before,
}
}
}

impl<'a> Handler for CheckEmbed<'a> {
fn set_point(&mut self, p: HandlerPoint) {
self.point = p;
}
}

impl<'a> VerylGrammarTrait for CheckEmbed<'a> {
fn embed_declaration(&mut self, arg: &EmbedDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let way = arg.identifier.identifier_token.to_string();
let lang = arg.identifier0.identifier_token.to_string();

if !EMBED_WAY.contains(&way.as_str()) {
self.errors.push(AnalyzerError::unknown_embed_way(
&way,
self.text,
&arg.identifier.identifier_token.token,
));
}

if !EMBED_LANG.contains(&lang.as_str()) {
self.errors.push(AnalyzerError::unknown_embed_lang(
&lang,
self.text,
&arg.identifier0.identifier_token.token,
));
}
}
Ok(())
}
}

const EMBED_WAY: [&str; 1] = ["inline"];
const EMBED_LANG: [&str; 1] = ["sv"];
23 changes: 23 additions & 0 deletions crates/analyzer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{Analyzer, AnalyzerError};
use veryl_metadata::Metadata;
use veryl_parser::Parser;

#[track_caller]
fn analyze(code: &str) -> Vec<AnalyzerError> {
let metadata: Metadata =
toml::from_str(&Metadata::create_default_toml("prj").unwrap()).unwrap();
Expand Down Expand Up @@ -427,6 +428,28 @@ fn unknown_attribute() {
assert!(matches!(errors[0], AnalyzerError::UnknownAttribute { .. }));
}

#[test]
fn unknown_embed_lang() {
let code = r#"
embed (inline) x{{{
}}}
"#;

let errors = analyze(code);
assert!(matches!(errors[0], AnalyzerError::UnknownEmbedLang { .. }));
}

#[test]
fn unknown_embed_way() {
let code = r#"
embed (x) sv{{{
}}}
"#;

let errors = analyze(code);
assert!(matches!(errors[0], AnalyzerError::UnknownEmbedWay { .. }));
}

#[test]
fn unknown_member() {
let code = r#"
Expand Down
11 changes: 11 additions & 0 deletions crates/emitter/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2731,6 +2731,16 @@ impl VerylWalker for Emitter {
}
}

/// Semantic action for non-terminal 'EmbedDeclaration'
fn embed_declaration(&mut self, arg: &EmbedDeclaration) {
if arg.identifier.identifier_token.to_string() == "inline" {
let text = arg.embed_content.embed_content_token.to_string();
let text = text.strip_prefix("{{{").unwrap();
let text = text.strip_suffix("}}}").unwrap();
self.str(text);
}
}

/// Semantic action for non-terminal 'DescriptionGroup'
fn description_group(&mut self, arg: &DescriptionGroup) {
for x in &arg.description_group_list {
Expand Down Expand Up @@ -2764,6 +2774,7 @@ impl VerylWalker for Emitter {
}
// file scope import is not emitted at SystemVerilog
DescriptionItem::ImportDeclaration(_) => (),
DescriptionItem::EmbedDeclaration(x) => self.embed_declaration(&x.embed_declaration),
};
}

Expand Down
12 changes: 12 additions & 0 deletions crates/formatter/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,18 @@ impl VerylWalker for Formatter {
}
}

/// Semantic action for non-terminal 'EmbedDeclaration'
fn embed_declaration(&mut self, arg: &EmbedDeclaration) {
self.embed(&arg.embed);
self.space(1);
self.l_paren(&arg.l_paren);
self.identifier(&arg.identifier);
self.r_paren(&arg.r_paren);
self.space(1);
self.identifier(&arg.identifier0);
self.embed_content(&arg.embed_content);
}

/// Semantic action for non-terminal 'DescriptionGroup'
fn description_group(&mut self, arg: &DescriptionGroup) {
for x in &arg.description_group_list {
Expand Down
1 change: 1 addition & 0 deletions crates/languageserver/src/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub const KEYWORDS: &[&str] = &[
"case",
"default",
"else",
"embed",
"enum",
"export",
"f32",
Expand Down
Loading

0 comments on commit 71b4904

Please sign in to comment.