diff --git a/tools/codegen/src/ast/mod.rs b/tools/codegen/src/ast/mod.rs index 6bad0cb..51b9b41 100644 --- a/tools/codegen/src/ast/mod.rs +++ b/tools/codegen/src/ast/mod.rs @@ -1,6 +1,8 @@ pub(crate) mod raw; pub(crate) mod verified; +pub use raw::SyntaxVersion; + pub use verified::{ Array, Ast, DefaultContent, DynVec, FieldDecl, FixVec, HasName, ImportStmt, ItemDecl, Option_, Primitive, Struct, Table, TopDecl, Union, diff --git a/tools/codegen/src/ast/raw/mod.rs b/tools/codegen/src/ast/raw/mod.rs index 6b97274..65b5564 100644 --- a/tools/codegen/src/ast/raw/mod.rs +++ b/tools/codegen/src/ast/raw/mod.rs @@ -1,16 +1,37 @@ use std::path::PathBuf; +#[cfg(feature = "compiler-plugin")] +use serde::{Deserialize, Serialize}; + use property::Property; mod utils; #[derive(Debug, Default, Property)] pub(crate) struct Ast { + syntax_version: Option, namespace: String, imports: Vec, decls: Vec, } +impl Default for SyntaxVersion { + fn default() -> Self { + Self { version: 1 } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Property)] +#[property(get(public))] +#[cfg_attr( + feature = "compiler-plugin", + derive(Deserialize, Serialize), + serde(deny_unknown_fields) +)] +pub struct SyntaxVersion { + version: usize, +} + #[derive(Debug, Clone, Property)] pub(crate) struct ImportStmt { name: String, diff --git a/tools/codegen/src/ast/raw/utils.rs b/tools/codegen/src/ast/raw/utils.rs index e27735e..dd5e020 100644 --- a/tools/codegen/src/ast/raw/utils.rs +++ b/tools/codegen/src/ast/raw/utils.rs @@ -3,6 +3,7 @@ use std::{ffi, fs, io::Read as _, path::Path, str::FromStr}; use pest::{error::Error as PestError, iterators::Pairs, Parser as _}; use same_file::is_same_file; +use crate::ast::raw::SyntaxVersion; use crate::{ ast::raw as ast, parser, @@ -184,6 +185,22 @@ impl parser::Parser { panic!("grammar should have only one EOI"); } match pair.as_rule() { + parser::Rule::syntax_version_stmt => { + let mut pair = pair.into_inner(); + let syntax_version = SyntaxVersion { + version: pair.next_usize(), + }; + pair.next_should_be_none(); + if ast.syntax_version.is_some() { + // compare ast.syntax_version and syntax_version + // panic if there is a conflict syntax_version + if ast.syntax_version != Some(syntax_version) { + panic!("all schema files' syntax version should be same"); + } + } else { + ast.syntax_version = Some(syntax_version); + } + } parser::Rule::import_stmt => { let mut pair = pair.into_inner(); let node = pair.next_import(path, imported_depth); @@ -265,6 +282,10 @@ impl parser::Parser { if !eoi { panic!("grammar should have only one EOI"); } + + if ast.syntax_version.is_none() { + ast.syntax_version = Some(SyntaxVersion::default()); + } Ok(()) } } diff --git a/tools/codegen/src/ast/verified/complete.rs b/tools/codegen/src/ast/verified/complete.rs index 70f6ac5..ac98095 100644 --- a/tools/codegen/src/ast/verified/complete.rs +++ b/tools/codegen/src/ast/verified/complete.rs @@ -213,7 +213,11 @@ impl super::Ast { let result = decls_result.get(decl.name()).unwrap(); decls.push(Rc::clone(result)); } + + let syntax_version = raw.syntax_version().unwrap().to_owned(); + Self { + syntax_version, namespace, imports, decls, diff --git a/tools/codegen/src/ast/verified/mod.rs b/tools/codegen/src/ast/verified/mod.rs index 3f49e40..2a5a817 100644 --- a/tools/codegen/src/ast/verified/mod.rs +++ b/tools/codegen/src/ast/verified/mod.rs @@ -12,11 +12,14 @@ mod recover; pub use default_content::DefaultContent; pub use has_name::HasName; +use crate::ast::SyntaxVersion; + type Deps<'a> = HashMap<&'a str, Rc>; #[derive(Debug, Property)] #[property(get(public))] pub struct Ast { + syntax_version: SyntaxVersion, namespace: String, imports: Vec, decls: Vec>, diff --git a/tools/codegen/src/ast/verified/recover.rs b/tools/codegen/src/ast/verified/recover.rs index 84b6096..ac73ba3 100644 --- a/tools/codegen/src/ast/verified/recover.rs +++ b/tools/codegen/src/ast/verified/recover.rs @@ -219,7 +219,10 @@ impl super::Ast { let result = decls_result.get(decl.name()).unwrap(); decls.push(Rc::clone(result)); } + + let syntax_version = ir.syntax_version().to_owned(); Self { + syntax_version, namespace, imports, decls, diff --git a/tools/codegen/src/grammar.pest b/tools/codegen/src/grammar.pest index 15c073b..254e450 100644 --- a/tools/codegen/src/grammar.pest +++ b/tools/codegen/src/grammar.pest @@ -78,8 +78,12 @@ path_super = @{ "../" } path = { path_super* ~ (identifier ~ "/")* ~ identifier } import_stmt = { "import" ~ (brk)+ ~ path ~ (brk)* ~ stmt_end } +syntax_version = @{ digit+ } +syntax_version_stmt = { "syntax" ~ (brk)* ~ "=" ~ (brk)* ~ syntax_version ~ (brk)* ~ stmt_end} + grammar = { SOI ~ (brk)* ~ + (syntax_version_stmt)? ~ (brk)* ~ (import_stmt ~ (brk)*)* ~ decl_stmt ~ ((brk)* ~ decl_stmt)* ~ (brk)* ~ diff --git a/tools/codegen/src/ir/from_ast.rs b/tools/codegen/src/ir/from_ast.rs index d57726a..4f4cd95 100644 --- a/tools/codegen/src/ir/from_ast.rs +++ b/tools/codegen/src/ir/from_ast.rs @@ -9,6 +9,7 @@ impl ToIntermediate for ast::Ast { type Ir = super::Ir; fn to_ir(&self) -> Self::Ir { Self::Ir { + syntax_version: self.syntax_version().to_owned(), namespace: self.namespace().to_owned(), imports: self.imports().iter().map(ToIntermediate::to_ir).collect(), decls: self.decls().iter().map(|decl| decl.to_ir()).collect(), diff --git a/tools/codegen/src/ir/mod.rs b/tools/codegen/src/ir/mod.rs index 90aa9b6..fcf2f87 100644 --- a/tools/codegen/src/ir/mod.rs +++ b/tools/codegen/src/ir/mod.rs @@ -8,10 +8,13 @@ use property::Property; pub use format::Format; pub(crate) use from_ast::ToIntermediate; +use crate::ast::SyntaxVersion; + /// Intermediate file. #[derive(Debug, Property, Deserialize, Serialize)] #[serde(deny_unknown_fields)] pub(crate) struct Ir { + syntax_version: SyntaxVersion, namespace: String, imports: Vec, #[serde(rename = "declarations")]