Merge pull request #24 from mist-go/generics

Generics
This commit is contained in:
2026-05-08 18:20:42 +02:00
committed by GitHub
4 changed files with 464 additions and 112 deletions
+13 -3
View File
@@ -3,13 +3,13 @@ use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct Identifier(pub String);
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Default)]
pub struct FieldList(pub Vec<(Identifier, Visibility, TypeExpr)>);
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Default)]
pub struct ParamList(pub Vec<VarDecl>);
#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Default)]
pub struct Block(pub Vec<Statement>);
#[derive(Debug, Clone, Serialize)]
@@ -62,6 +62,8 @@ pub enum BinaryOp {
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
And,
Or,
}
#[derive(Debug, Clone, Serialize)]
@@ -75,10 +77,12 @@ pub enum TopLevelKind {
EnumDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
fields: Vec<EnumItem>,
},
StructDecl {
visibility: Visibility,
generics: Generics,
name: Identifier,
fields: FieldList,
},
@@ -86,12 +90,16 @@ pub enum TopLevelKind {
ClassDecl {
visibility: Visibility,
name: Identifier,
generics: Generics,
fields: Vec<VarDeclStmt>,
constructor: ClassConstructor,
methods: Vec<FunctionDecl>,
},
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct Generics(pub Vec<(Identifier, Vec<Path>)>);
#[derive(Debug, Clone, Serialize)]
pub enum Pattern {
NamedTuple(Path, Vec<Identifier>),
@@ -112,6 +120,7 @@ pub enum EnumItem {
#[derive(Debug, Clone, Serialize)]
pub struct ClassConstructor {
pub visibility: Visibility,
pub generics: Generics,
pub params: ParamList,
pub body: Block,
}
@@ -120,6 +129,7 @@ pub struct ClassConstructor {
pub struct FunctionDecl {
pub visibility: Visibility,
pub name: Identifier,
pub generics: Generics,
pub params: ParamList,
pub return_type: TypeExpr,
pub body: Block,
+349 -81
View File
@@ -1,59 +1,121 @@
// ======================================================
// LEXICAL
// ======================================================
WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
COMMENT = _{ "//" ~ (!"\n" ~ ANY)* }
program = { SOI ~ top_level* ~ EOI }
// ------------------------------------------------------
// PRIMITIVES
// ------------------------------------------------------
// primitives
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
integer = @{ ASCII_DIGIT+ }
float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
boolean = { "true" | "false" }
string_lit = { "\"" ~ inner_str ~ "\"" }
inner_str = @{ (!"\"" ~ ("\\\"" | ANY))* }
static_path = { identifier ~ ("::" ~ identifier)* }
// pattern
tuple_pattern = { "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" }
named_tuple_pattern = { static_path ~ "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" }
struct_pattern = { static_path ~ "{" ~ (identifier ~ ("," ~ identifier)*)? ~ "}" }
pattern = _{ named_tuple_pattern | tuple_pattern | struct_pattern | literal | static_path }
integer = @{ ASCII_DIGIT+ }
float = @{
ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+
}
boolean = {
"true"
| "false"
}
string_lit = {
"\"" ~ inner_str ~ "\""
}
inner_str = @{
(!"\"" ~ ("\\\"" | ANY))*
}
semicolon = _{ ";" }
static_path = {
identifier ~ ("::" ~ identifier)*
}
// ======================================================
// PROGRAM
// ======================================================
program = {
SOI ~ top_level* ~ EOI
}
// ======================================================
// MODIFIERS
// ======================================================
export = { "public" }
mutable = { "mut" }
var = { "var" }
var_decl = { (var | type_expr) ~ mutable? ~ pattern }
semicolon = _{ ";" }
// ================= CLASS =================
class_constructor = {
export? ~ "constructor" ~ "(" ~ param_list? ~ ")" ~ block
// ======================================================
// GENERICS
// ======================================================
generic = { identifier ~ (":" ~ static_path ~ ("+" ~ static_path)*)? }
generics = { "<" ~ (generic ~ ("," ~ generic)*)? ~ ">" }
// ======================================================
// TYPES
// ======================================================
tuple_type = {
"(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")"
}
class_fields = { var_decl_statement* }
self_param = { "self" ~ mutable? ~ deref_px? }
method = {
export? ~ type_expr ~ identifier ~ "(" ~ self_param? ~ param_list? ~ ")" ~ block
path_type = {
static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")?
}
class_decl = {
export? ~ "class" ~ identifier ~ "{" ~ class_fields ~ class_constructor ~ method* ~ "}"
ref_type = {
mutable? ~ "*"
}
// ================= TOP LEVEL =================
type_expr = {
(path_type | tuple_type) ~ ref_type*
}
enum_named = { identifier }
enum_tuple = { identifier ~ tuple_type }
enum_struct = { identifier ~ "{" ~ field_list ~ "}" }
// ======================================================
// LITERALS
// ======================================================
enum_field = _{ enum_tuple | enum_struct | enum_named }
literal = {
float
| integer
| boolean
| string_lit
}
enum_fields = _{ enum_field ~ ("," ~ enum_field)* ~ ","? }
// ======================================================
// PATTERNS
// ======================================================
enum_decl = { export? ~ "enum" ~ identifier ~ "{" ~ enum_fields ~ "}" }
tuple_pattern = {
"(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")"
}
top_level = { (attributes ~ (import | function_decl | struct_decl | enum_decl | class_decl | mod_package)) | mod_attribute }
named_tuple_pattern = {
static_path ~ "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")"
}
struct_pattern = {
static_path ~ "{" ~ (identifier ~ ("," ~ identifier)*)? ~ "}"
}
pattern = _{
named_tuple_pattern
| tuple_pattern
| struct_pattern
| literal
| static_path
}
// ======================================================
// ATTRIBUTES / META
// ======================================================
attribute = {
"#" ~ "[" ~ meta ~ "]"
@@ -71,30 +133,132 @@ meta_list = {
meta ~ ("," ~ meta)* ~ ","?
}
attributes = { attribute* }
attributes = {
attribute*
}
import = { "use" ~ "<" ~ static_path ~ ">" ~ semicolon }
// ======================================================
// DECLARATION HELPERS
// ======================================================
mod_package = { "mod" ~ identifier ~ semicolon }
var_decl = {
(var | type_expr) ~ mutable? ~ pattern
}
field_list = { field ~ ("," ~ field)* ~ ","? }
field = { export? ~ type_expr ~ identifier }
field = {
export? ~ type_expr ~ identifier
}
param_list = { var_decl ~ ("," ~ var_decl)* ~ ","? }
field_list = {
field ~ ("," ~ field)* ~ ","?
}
param_list = {
var_decl ~ ("," ~ var_decl)* ~ ","?
}
// ======================================================
// IMPORTS / MODULES
// ======================================================
import = {
"use" ~ "<" ~ static_path ~ ">" ~ semicolon
}
mod_package = {
"mod" ~ identifier ~ semicolon
}
// ======================================================
// STRUCTS
// ======================================================
struct_decl = {
export? ~ "struct" ~ identifier ~ "{" ~ field_list? ~ "}"
export? ~ "struct" ~ identifier ~ generics? ~ "{" ~ field_list? ~ "}"
}
// ======================================================
// ENUMS
// ======================================================
enum_named = {
identifier
}
enum_tuple = {
identifier ~ tuple_type
}
enum_struct = {
identifier ~ "{" ~ field_list ~ "}"
}
enum_field = _{
enum_tuple
| enum_struct
| enum_named
}
enum_fields = _{
enum_field ~ ("," ~ enum_field)* ~ ","?
}
enum_decl = {
export? ~ "enum" ~ identifier ~ generics? ~ "{" ~ enum_fields ~ "}"
}
// ======================================================
// CLASSES
// ======================================================
class_constructor = {
export? ~ "constructor" ~ generics? ~ "(" ~ param_list? ~ ")" ~ block
}
class_fields = {
var_decl_statement*
}
self_param = {
"self" ~ mutable? ~ deref_px?
}
method = {
export? ~ type_expr ~ identifier ~ generics? ~ "(" ~ self_param? ~ param_list? ~ ")" ~ block
}
class_decl = {
export? ~ "class" ~ identifier ~ generics? ~ "{" ~ class_fields ~ class_constructor ~ method* ~ "}"
}
// ======================================================
// FUNCTIONS
// ======================================================
function_decl = {
export? ~ type_expr ~ identifier ~ "(" ~ param_list? ~ ")" ~ block
}
// ================= STATEMENTS =================
// ======================================================
// TOP LEVEL
// ======================================================
block = { "{" ~ statement_list ~ "}" }
top_level = {
(attributes ~ (import | function_decl | struct_decl | enum_decl | class_decl | mod_package))
| mod_attribute
}
statement_list = { statement* }
// ======================================================
// STATEMENTS
// ======================================================
block = {
"{" ~ statement_list ~ "}"
}
statement_list = {
statement*
}
statement = _{
expr_stmt
@@ -111,28 +275,54 @@ statement = _{
| block
}
// --- basic statements ---
// ------------------------------------------------------
// BASIC STATEMENTS
// ------------------------------------------------------
expr_stmt = { expr ~ semicolon }
expr_stmt = {
expr ~ semicolon
}
return_stmt = { "return" ~ expr? ~ semicolon }
return_stmt = {
"return" ~ expr? ~ semicolon
}
break_stmt = { "break" ~ semicolon }
break_stmt = {
"break" ~ semicolon
}
continue_stmt = { "continue" ~ semicolon }
continue_stmt = {
"continue" ~ semicolon
}
var_decl_statement = { var_decl ~ ("=" ~ expr)? ~ semicolon }
var_decl_statement = {
var_decl ~ ("=" ~ expr)? ~ semicolon
}
assign_statement = { expr ~ "=" ~ expr ~ semicolon }
assign_statement = {
expr ~ "=" ~ expr ~ semicolon
}
else_if = { "else" ~ "if" ~ "(" ~ expr ~ ")" ~ statement }
// ------------------------------------------------------
// CONDITIONALS
// ------------------------------------------------------
else_if_list = { else_if* }
else_if = {
"else" ~ "if" ~ "(" ~ expr ~ ")" ~ statement
}
else_if_list = {
else_if*
}
if_stmt = {
"if" ~ "(" ~ expr ~ ")" ~ statement ~ else_if_list ~ ("else" ~ statement)?
}
// ------------------------------------------------------
// LOOPS
// ------------------------------------------------------
while_stmt = {
"while" ~ "(" ~ expr ~ ")" ~ statement
}
@@ -145,31 +335,42 @@ for_stmt = {
"for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement
}
match_item = { pattern ~ "=>" ~ block }
// ------------------------------------------------------
// MATCH
// ------------------------------------------------------
match_item = {
pattern ~ "=>" ~ block
}
match_stmt = {
"match" ~ "(" ~ expr ~ ")" ~ "{" ~ match_item* ~ "}"
}
// ================= EXPRESSIONS =================
tuple_type = { "(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")" }
path_type = { static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? }
ref_type = { mutable? ~ "*" }
type_expr = { (path_type | tuple_type) ~ ref_type* }
// ======================================================
// EXPRESSIONS
// ======================================================
// ------------------------------------------------------
// TUPLES
// ------------------------------------------------------
tuple = {
"(" ~ (expr ~ ("," ~ expr)*)? ~ ")"
}
// ------------------------------------------------------
// MACROS
// ------------------------------------------------------
macro_inner_v = {
"(" ~ macro_inner_v* ~ ")"
| (!("(" | ")") ~ ANY)
}
tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
literal = {
float
| integer
| boolean
| string_lit
}
// ------------------------------------------------------
// PRIMARY EXPRESSIONS
// ------------------------------------------------------
primary = {
literal
@@ -177,6 +378,38 @@ primary = {
| tuple
}
// ------------------------------------------------------
// POSTFIX EXPRESSIONS
// ------------------------------------------------------
field_px = {
"." ~ identifier
}
call_px = {
"(" ~ (expr ~ ("," ~ expr)*)? ~ ")"
}
macro_call_px = {
"!" ~ "(" ~ macro_inner_v* ~ ")"
}
struct_field_decl = {
identifier ~ ":" ~ expr
}
struct_px = {
"{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ ","? ~ "}"
}
index_px = {
"[" ~ expr ~ "]"
}
binary_px = {
bin_op ~ expr
}
postfix = {
field_px
| call_px
@@ -186,14 +419,29 @@ postfix = {
| binary_px
}
field_px = { "." ~ identifier }
call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
macro_call_px = { "!" ~ "(" ~ macro_inner_v* ~ ")" }
struct_px = { "{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ ","? ~ "}" }
index_px = { "[" ~ expr ~ "]" }
binary_px = { bin_op ~ expr }
bin_op = { "<=" | ">=" | "==" | "!=" | "+" | "-" | "*" | "/" | "%" | "<" | ">" }
struct_field_decl = { identifier ~ ":" ~ expr }
// ------------------------------------------------------
// PREFIX EXPRESSIONS
// ------------------------------------------------------
deref_px = {
"*"
}
mut_ref_px = {
"&" ~ mutable
}
ref_px = {
"&"
}
new_px = {
"new"
}
not_px = {
"!"
}
prefix = {
deref_px
@@ -203,13 +451,33 @@ prefix = {
| not_px
}
deref_px = { "*" }
mut_ref_px = { "&" ~ mutable }
ref_px = { "&" }
new_px = { "new" }
not_px = { "!" }
prefix_list = {
prefix*
}
prefix_list = { prefix* }
// ------------------------------------------------------
// OPERATORS
// ------------------------------------------------------
bin_op = {
"<="
| ">="
| "=="
| "!="
| "&&"
| "||"
| "+"
| "-"
| "*"
| "/"
| "%"
| "<"
| ">"
}
// ------------------------------------------------------
// EXPRESSIONS
// ------------------------------------------------------
expr = {
prefix_list ~ primary ~ postfix*
+48 -15
View File
@@ -211,18 +211,45 @@ impl From<pest::iterators::Pair<'_, Rule>> for ClassConstructor {
let visibility = Visibility::from(&mut inner);
let generics = consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default();
let params = consume_rule(&mut inner, Rule::param_list)
.map(ParamList::from)
.unwrap_or_else(|| ParamList(Vec::new()));
Self {
visibility,
generics,
params,
body: Block::from(inner.next().unwrap()),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for Generics {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
let inner = pair.clone().into_inner();
match rule {
Rule::generics => Generics(
inner
.map(|pair| {
let mut inner = pair.into_inner();
(
Identifier::from(inner.next().unwrap()),
inner.map(Path::from).collect(),
)
})
.collect(),
),
_ => unimplemented!("{rule:#?}"),
}
}
}
impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let rule = pair.as_rule();
@@ -233,22 +260,21 @@ impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::from(pair)),
Rule::struct_decl => {
let visibility = Visibility::from(&mut inner);
let name = Identifier::from(inner.next().unwrap());
let fields_pair = inner.next().unwrap();
let fields = FieldList::from(fields_pair);
TopLevelKind::StructDecl {
visibility,
name,
fields,
}
}
Rule::struct_decl => TopLevelKind::StructDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner.next().map(FieldList::from).unwrap_or_default(),
},
Rule::class_decl => TopLevelKind::ClassDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner
.next()
.unwrap()
@@ -262,6 +288,9 @@ impl From<pest::iterators::Pair<'_, Rule>> for TopLevelKind {
Rule::enum_decl => TopLevelKind::EnumDecl {
visibility: Visibility::from(&mut inner),
name: Identifier::from(inner.next().unwrap()),
generics: consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default(),
fields: inner.map(EnumItem::from).collect(),
},
@@ -498,6 +527,8 @@ impl From<pest::iterators::Pair<'_, Rule>> for Postfix {
">" => BinaryOp::GreaterThan,
"<=" => BinaryOp::LessThanOrEqual,
">=" => BinaryOp::GreaterThanOrEqual,
"&&" => BinaryOp::And,
"||" => BinaryOp::Or,
_ => {
unimplemented!("Binary operator not implemented yet: {}", op_pair.as_str())
@@ -592,12 +623,13 @@ impl From<pest::iterators::Pair<'_, Rule>> for VarDecl {
impl From<pest::iterators::Pair<'_, Rule>> for FunctionDecl {
fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self {
let mut inner = pair.into_inner();
let visibility = Visibility::from(&mut inner);
let return_type = TypeExpr::from(inner.next().unwrap());
let name = Identifier::from(inner.next().unwrap());
let generics = consume_rule(&mut inner, Rule::generics)
.map(Generics::from)
.unwrap_or_default();
let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| {
let mut param_inner = param.into_inner();
let name = Pattern::Id(Identifier(String::from("self")));
@@ -642,6 +674,7 @@ impl From<pest::iterators::Pair<'_, Rule>> for FunctionDecl {
Self {
visibility,
name,
generics,
params,
return_type,
body,
+52 -11
View File
@@ -1,6 +1,6 @@
use parser::ast::{
Attribute, BinaryOp, Block, EnumItem, Expression, FunctionDecl, Identifier, Literal, Path,
Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr,
Attribute, BinaryOp, Block, EnumItem, Expression, FunctionDecl, Generics, Identifier, Literal,
Path, Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr,
TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, Visibility,
};
@@ -238,6 +238,8 @@ impl GetRust for Postfix {
BinaryOp::GreaterThan => ">",
BinaryOp::LessThanOrEqual => "<=",
BinaryOp::GreaterThanOrEqual => ">=",
BinaryOp::And => "&&",
BinaryOp::Or => "||",
};
format!(" {} {}", op_str, rhs.get_rust())
}
@@ -314,12 +316,14 @@ impl ToRust for TopLevelKind {
Self::StructDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}struct {} {{",
"{}struct {}{} {{",
visibility.get_rust(),
name.get_rust()
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
@@ -334,12 +338,14 @@ impl ToRust for TopLevelKind {
Self::EnumDecl {
visibility,
name,
generics,
fields,
} => {
cg.addln(&format!(
"{}enum {} {{",
"{}enum {}{} {{",
visibility.get_rust(),
name.get_rust()
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
@@ -353,15 +359,17 @@ impl ToRust for TopLevelKind {
Self::ClassDecl {
visibility,
name,
generics,
fields,
constructor,
methods,
} => {
// Struct decl
cg.addln(&format!(
"{}struct {} {{",
"{}struct {}{} {{",
visibility.get_rust(),
name.get_rust()
name.get_rust(),
generics.get_rust()
));
cg.indent += 1;
@@ -386,8 +394,9 @@ impl ToRust for TopLevelKind {
.join(", ");
cg.add_indentedln(&format!(
"{}fn new({}) -> Self {{",
"{}fn new{}({}) -> Self {{",
constructor.visibility.get_rust(),
constructor.generics.get_rust(),
params_str
));
cg.indent += 1;
@@ -422,8 +431,9 @@ impl ToRust for TopLevelKind {
// Constructor function
cg.add_indentedln(&format!(
"{}fn construct_class(&mut self, {}) {{",
"{}fn construct_class{}(&mut self, {}) {{",
constructor.visibility.get_rust(),
constructor.generics.get_rust(),
params_str
));
cg.indent += 1;
@@ -577,9 +587,10 @@ impl ToRust for FunctionDecl {
.join(", ");
cg.add_indentedln(&format!(
"{}fn {}({}) -> {} {{",
"{}fn {}{}({}) -> {} {{",
self.visibility.get_rust(),
self.name.get_rust(),
self.generics.get_rust(),
params_str,
self.return_type.get_rust()
));
@@ -701,6 +712,36 @@ impl GetRust for Pattern {
}
}
impl GetRust for Generics {
fn get_rust(&self) -> String {
if self.0.len() == 0 {
String::new()
} else {
format!(
"<{}>",
self.0
.iter()
.map(|generic| generic.0.get_rust()
+ &(if generic.1.len() == 0 {
String::new()
} else {
format!(
": {}",
generic
.1
.iter()
.map(Path::get_rust)
.collect::<Vec<_>>()
.join("+")
)
}))
.collect::<Vec<_>>()
.join(", ")
)
}
}
}
pub fn get_static_type_path(path: &Path) -> String {
let rust_path = path.get_rust();