Merge pull request #20 from mist-go/attributes

Attributes
This commit is contained in:
2026-05-05 15:11:22 +02:00
committed by GitHub
6 changed files with 253 additions and 54 deletions
+1
View File
@@ -8,6 +8,7 @@ target
# MSVC Windows builds of rustc generate these, which store debugging information # MSVC Windows builds of rustc generate these, which store debugging information
*.pdb *.pdb
*.exe
# Generated by cargo mutants # Generated by cargo mutants
# Contains mutation testing data # Contains mutation testing data
+32 -11
View File
@@ -17,10 +17,22 @@ pub enum TypePostfix {
RefMut, RefMut,
} }
#[derive(Debug, Clone, Serialize)]
pub enum Attribute {
/// #[test]
Path(Path),
/// #[name = "value"]
NameValue { path: Path, value: Literal },
/// #[derive(Clone, Copy)]
List { path: Path, items: Vec<Attribute> },
}
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum TypeExprKind { pub enum TypeExprKind {
Path(StaticPath), Path(Path),
PathParams(StaticPath, Vec<TypeExpr>), PathParams(Path, Vec<TypeExpr>),
Tuple(Vec<TypeExpr>), Tuple(Vec<TypeExpr>),
} }
@@ -28,7 +40,7 @@ pub enum TypeExprKind {
pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>); pub struct TypeExpr(pub TypeExprKind, pub Vec<TypePostfix>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct StaticPath(pub Vec<String>); pub struct Path(pub Vec<String>);
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum BinaryOp { pub enum BinaryOp {
@@ -46,8 +58,12 @@ pub enum BinaryOp {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum TopLevel { pub struct TopLevel(pub TopLevelKind, pub Vec<Attribute>);
Include(StaticPath),
#[derive(Debug, Clone, Serialize)]
pub enum TopLevelKind {
ModAttribute,
Include(Path),
StructDecl { StructDecl {
export: bool, export: bool,
name: String, name: String,
@@ -137,15 +153,20 @@ pub struct ForStmt {
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum Expression { pub enum Expression {
Path(StaticPath), Literal(Literal),
IntLiteral(i64), Path(Path),
FloatLiteral(f64),
BoolLiteral(bool),
StringLiteral(String),
TupleLiteral(Vec<Expression>),
Fix { Fix {
initial: Box<Expression>, initial: Box<Expression>,
prefixes: Vec<Prefix>, prefixes: Vec<Prefix>,
postfixes: Vec<Postfix>, postfixes: Vec<Postfix>,
}, },
} }
#[derive(Debug, Clone, Serialize)]
pub enum Literal {
String(String),
Int(i64),
Float(f64),
Bool(bool),
Tuple(Vec<Expression>),
}
+22 -4
View File
@@ -19,7 +19,25 @@ var_decl = { type_expr ~ mutable? ~ identifier }
// ================= TOP LEVEL ================= // ================= TOP LEVEL =================
top_level = _{ import | function_decl | struct_decl } attribute = {
"#" ~ "[" ~ meta ~ "]"
}
mod_attribute = {
"#" ~ "!" ~ "[" ~ meta ~ "]"
}
meta = {
static_path ~ ("=" ~ primary | "(" ~ meta_list? ~ ")")?
}
meta_list = {
meta ~ ("," ~ meta)* ~ ","?
}
attributes = { attribute* }
top_level = { (attributes ~ (import | function_decl | struct_decl)) | mod_attribute }
import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" } import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" }
@@ -90,8 +108,8 @@ macro_inner_v = {
tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
primary = { primary = {
integer float
| float | integer
| boolean | boolean
| string_lit | string_lit
| static_path | static_path
@@ -110,7 +128,7 @@ postfix = {
field_px = { "." ~ identifier } field_px = { "." ~ identifier }
call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
macro_call_px = { "!" ~ "(" ~ macro_inner_v* ~ ")" } macro_call_px = { "!" ~ "(" ~ macro_inner_v* ~ ")" }
struct_px = { "{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ "}" } struct_px = { "{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ ","? ~ "}" }
index_px = { "[" ~ expr ~ "]" } index_px = { "[" ~ expr ~ "]" }
binary_px = { bin_op ~ expr } binary_px = { bin_op ~ expr }
bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" } bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" }
+121 -23
View File
@@ -18,8 +18,8 @@ pub fn parse(source: &str) -> Result<Vec<TopLevel>, ParseError> {
let mut statements = vec![]; let mut statements = vec![];
for pair in pairs.next().unwrap().into_inner() { for pair in pairs.next().unwrap().into_inner() {
if let Ok(stmt) = TopLevel::try_from(pair) { if pair.as_rule() != Rule::EOI {
statements.push(stmt); statements.push(TopLevel::from(pair));
} }
} }
@@ -67,7 +67,7 @@ impl From<pest::iterators::Pair<'_, Rule>> for TypeExprKind {
match rule { match rule {
Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()), Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()),
Rule::path_type => { Rule::path_type => {
let path = StaticPath::from(inner.next().unwrap()); let path = Path::from(inner.next().unwrap());
let params = inner.map(TypeExpr::from).collect::<Vec<_>>(); let params = inner.map(TypeExpr::from).collect::<Vec<_>>();
if params.len() == 0 { if params.len() == 0 {
@@ -81,12 +81,10 @@ impl From<pest::iterators::Pair<'_, Rule>> for TypeExprKind {
} }
} }
impl From<pest::iterators::Pair<'_, Rule>> for StaticPath { impl From<pest::iterators::Pair<'_, Rule>> for Path {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
match pair.as_rule() { match pair.as_rule() {
Rule::static_path => { Rule::static_path => Path(pair.into_inner().map(|i| i.as_str().to_string()).collect()),
StaticPath(pair.into_inner().map(|i| i.as_str().to_string()).collect())
}
_ => unimplemented!("{pair:#?}"), _ => unimplemented!("{pair:#?}"),
} }
} }
@@ -120,14 +118,91 @@ impl From<pest::iterators::Pair<'_, Rule>> for ParamList {
} }
} }
impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel { impl From<pest::iterators::Pair<'_, Rule>> for Attribute {
type Error = (); fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
fn try_from(pair: pest::iterators::Pair<Rule>) -> Result<Self, ()> { match pair.as_rule() {
Rule::attribute => {
// unwrap #[ ... ]
Attribute::from(pair.into_inner().next().unwrap())
}
Rule::meta => {
let mut inner = pair.into_inner();
// first item is always the path
let path = Path::from(inner.next().unwrap());
// check what comes next
match inner.next() {
None => {
// #[path]
Attribute::Path(path)
}
Some(next) => match next.as_rule() {
Rule::primary => {
// #[path = literal]
Attribute::NameValue {
path,
value: Literal::from(next),
}
}
Rule::meta_list => {
// #[path(...)]
let items = next.into_inner().map(Attribute::from).collect();
Attribute::List { path, items }
}
_ => unreachable!("unexpected rule in meta: {:?}", next.as_rule()),
},
}
}
Rule::meta_list => {
// This case usually won't be hit directly,
// but it's nice to keep it safe if reused
let items = pair.into_inner().map(Attribute::from).collect::<Vec<_>>();
// NOTE: this shouldn't normally construct an Attribute alone
// but you can panic or wrap depending on your design
panic!("meta_list should be handled inside meta: {:?}", items);
}
_ => unreachable!("unexpected rule: {:?}", pair.as_rule()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TopLevel {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let attributes = inner
.next()
.unwrap()
.into_inner()
.map(Attribute::from)
.collect::<Vec<_>>();
TopLevel(
inner
.next()
.map(TopLevelKind::from)
.unwrap_or(TopLevelKind::ModAttribute),
attributes,
)
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule(); let rule = pair.as_rule();
let mut inner = pair.into_inner(); let mut inner = pair.into_inner();
match rule { match rule {
Rule::import => Ok(TopLevel::Include(StaticPath::from(inner.next().unwrap()))), Rule::import => TopLevelKind::Include(Path::from(inner.next().unwrap())),
Rule::function_decl => { Rule::function_decl => {
let export = if let Some(first) = inner.peek() { let export = if let Some(first) = inner.peek() {
@@ -152,13 +227,13 @@ impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel {
let body = Block::from(inner.next().unwrap()); let body = Block::from(inner.next().unwrap());
Ok(TopLevel::FunctionDecl { TopLevelKind::FunctionDecl {
export, export,
name, name,
params, params,
return_type, return_type,
body, body,
}) }
} }
Rule::struct_decl => { Rule::struct_decl => {
@@ -176,14 +251,12 @@ impl TryFrom<pest::iterators::Pair<'_, Rule>> for TopLevel {
let fields_pair = inner.next().unwrap(); let fields_pair = inner.next().unwrap();
let fields = FieldList::from(fields_pair); let fields = FieldList::from(fields_pair);
Ok(TopLevel::StructDecl { TopLevelKind::StructDecl {
export, export,
name, name,
fields, fields,
})
} }
}
Rule::EOI => Err(()),
_ => unimplemented!("{rule:#?}"), _ => unimplemented!("{rule:#?}"),
} }
} }
@@ -262,6 +335,23 @@ impl From<pest::iterators::Pair<'_, Rule>> for Statement {
} }
} }
impl From<pest::iterators::Pair<'_, Rule>> for Literal {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::primary => Self::from(inner.next().unwrap()),
Rule::integer => Literal::Int(pair.as_str().parse::<i64>().unwrap()),
Rule::float => Literal::Float(pair.as_str().parse::<f64>().unwrap()),
Rule::boolean => Literal::Bool(pair.as_str().parse::<bool>().unwrap()),
Rule::string_lit => Literal::String(inner.as_str().to_string()),
Rule::tuple => Literal::Tuple(inner.map(Expression::from).collect()),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Expression { impl From<pest::iterators::Pair<'_, Rule>> for Expression {
fn from(pair: pest::iterators::Pair<Rule>) -> Self { fn from(pair: pest::iterators::Pair<Rule>) -> Self {
let rule = pair.as_rule(); let rule = pair.as_rule();
@@ -292,12 +382,20 @@ impl From<pest::iterators::Pair<'_, Rule>> for Expression {
} }
} }
Rule::primary => Expression::from(inner.next().unwrap()), Rule::primary => Expression::from(inner.next().unwrap()),
Rule::static_path => Expression::Path(StaticPath::from(pair)), Rule::static_path => Expression::Path(Path::from(pair)),
Rule::integer => Expression::IntLiteral(pair.as_str().parse::<i64>().unwrap()), Rule::integer => {
Rule::float => Expression::FloatLiteral(pair.as_str().parse::<f64>().unwrap()), Expression::Literal(Literal::Int(pair.as_str().parse::<i64>().unwrap()))
Rule::boolean => Expression::BoolLiteral(pair.as_str().parse::<bool>().unwrap()), }
Rule::string_lit => Expression::StringLiteral(inner.as_str().to_string()), Rule::float => {
Rule::tuple => Expression::TupleLiteral(inner.map(Expression::from).collect()), Expression::Literal(Literal::Float(pair.as_str().parse::<f64>().unwrap()))
}
Rule::boolean => {
Expression::Literal(Literal::Bool(pair.as_str().parse::<bool>().unwrap()))
}
Rule::string_lit => Expression::Literal(Literal::String(inner.as_str().to_string())),
Rule::tuple => {
Expression::Literal(Literal::Tuple(inner.map(Expression::from).collect()))
}
_ => unimplemented!("{rule:#?}"), _ => unimplemented!("{rule:#?}"),
} }
} }
+65 -14
View File
@@ -1,6 +1,7 @@
use parser::ast::{ use parser::ast::{
BinaryOp, Block, Expression, IfStmt, Postfix, Prefix, Statement, StaticPath, TopLevel, Attribute, BinaryOp, Block, Expression, IfStmt, Literal, Path, Postfix, Prefix, Statement,
TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, WhileStmt, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, VarDecl,
VarDeclStmt, WhileStmt,
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -105,15 +106,14 @@ impl GetRust for TypeExprKind {
} }
} }
impl GetRust for Expression { impl GetRust for Literal {
fn get_rust(&self) -> String { fn get_rust(&self) -> String {
match self { match self {
Expression::Path(path) => path.get_rust(), Self::Int(n) => n.to_string(),
Expression::IntLiteral(n) => n.to_string(), Self::Float(n) => format!("{n:?}"),
Expression::FloatLiteral(n) => n.to_string(), Self::Bool(b) => b.to_string(),
Expression::BoolLiteral(b) => b.to_string(), Self::String(s) => format!("\"{s}\""),
Expression::StringLiteral(s) => format!("\"{s}\""), Self::Tuple(t) => {
Expression::TupleLiteral(t) => {
format!( format!(
"({})", "({})",
t.iter() t.iter()
@@ -122,6 +122,15 @@ impl GetRust for Expression {
.join(", ") .join(", ")
) )
} }
}
}
}
impl GetRust for Expression {
fn get_rust(&self) -> String {
match self {
Expression::Path(path) => path.get_rust(),
Expression::Literal(literal) => literal.get_rust(),
Expression::Fix { Expression::Fix {
initial, initial,
prefixes, prefixes,
@@ -219,12 +228,54 @@ impl ToRust for Block {
impl ToRust for TopLevel { impl ToRust for TopLevel {
fn to_rust(&self, cg: &mut RustCodegen) { fn to_rust(&self, cg: &mut RustCodegen) {
match &self.0 {
TopLevelKind::ModAttribute => {
for attr in &self.1 {
cg.addln(&format!("#![{}]", attr.get_rust()));
}
}
_ => {
for attr in &self.1 {
cg.addln(&format!("#[{}]", attr.get_rust()));
}
}
}
self.0.to_rust(cg);
}
}
impl GetRust for Attribute {
fn get_rust(&self) -> String {
match self { match self {
TopLevel::Include(path) => { Self::Path(path) => path.get_rust(),
Self::NameValue { path, value } => {
format!("{} = {}", path.get_rust(), value.get_rust())
}
Self::List { path, items } => {
format!(
"{}({})",
path.get_rust(),
items
.iter()
.map(Attribute::get_rust)
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
}
impl ToRust for TopLevelKind {
fn to_rust(&self, cg: &mut RustCodegen) {
match self {
Self::ModAttribute => {}
Self::Include(path) => {
cg.addln(&format!("use {};", path.get_rust())); cg.addln(&format!("use {};", path.get_rust()));
} }
TopLevel::StructDecl { Self::StructDecl {
export, export,
name, name,
fields, fields,
@@ -242,7 +293,7 @@ impl ToRust for TopLevel {
cg.addln("}\n"); cg.addln("}\n");
} }
TopLevel::FunctionDecl { Self::FunctionDecl {
export, export,
name, name,
params, params,
@@ -359,7 +410,7 @@ impl GetRust for VarDecl {
} }
} }
impl GetRust for StaticPath { impl GetRust for Path {
fn get_rust(&self) -> String { fn get_rust(&self) -> String {
self.0.join("::") self.0.join("::")
} }
@@ -374,7 +425,7 @@ impl GetRust for TypePostfix {
} }
} }
pub fn get_static_type_path(path: &StaticPath) -> String { pub fn get_static_type_path(path: &Path) -> String {
let rust_path = path.get_rust(); let rust_path = path.get_rust();
if rust_path == "void" { if rust_path == "void" {
+11 -1
View File
@@ -1,3 +1,13 @@
#![allow(unused_mut)]
#[derive(Debug)]
public struct ApiCall {
i32 x,
i32 y,
}
void main() { void main() {
(i32, i32, str*) my_tuple = (10, 20, "hello, world"); ApiCall call = ApiCall { x: 10, y: 12 };
println!("{call:?}");
} }