+23
-14
@@ -26,7 +26,7 @@ use crate::transpiler::{
|
|||||||
|
|
||||||
static MARKER_COUNTER: AtomicU64 = AtomicU64::new(0);
|
static MARKER_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
const KEYWORDS: [&'static str; 22] = [
|
const KEYWORDS: [&'static str; 23] = [
|
||||||
"if",
|
"if",
|
||||||
"else",
|
"else",
|
||||||
"for",
|
"for",
|
||||||
@@ -49,6 +49,7 @@ const KEYWORDS: [&'static str; 22] = [
|
|||||||
"override",
|
"override",
|
||||||
"module ",
|
"module ",
|
||||||
"void ",
|
"void ",
|
||||||
|
"virtual ",
|
||||||
];
|
];
|
||||||
|
|
||||||
fn keyword_completion_items() -> impl Iterator<Item = CompletionItem> {
|
fn keyword_completion_items() -> impl Iterator<Item = CompletionItem> {
|
||||||
@@ -1630,11 +1631,11 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
// Struct/Class
|
// Struct/Class
|
||||||
// =========================
|
// =========================
|
||||||
|
|
||||||
if matches!(curr_scope, Scope::Struct) {
|
if matches!(curr_scope, Scope::Class) {
|
||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "field".into(),
|
label: "virtual".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
insert_text: Some("$1 $2,".into()),
|
insert_text: Some("pub virtual $1 $2()\n{\n\t$3\n}".into()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
sort_text: Some("0000".into()),
|
sort_text: Some("0000".into()),
|
||||||
preselect: Some(true),
|
preselect: Some(true),
|
||||||
@@ -1642,9 +1643,19 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
});
|
});
|
||||||
|
|
||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "pub field".into(),
|
label: "override".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
insert_text: Some("pub $1 $2,".into()),
|
insert_text: Some("$1 $2() override$3\n{\n\t$4\n}".into()),
|
||||||
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
|
sort_text: Some("0000".into()),
|
||||||
|
preselect: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
items.push(CompletionItem {
|
||||||
|
label: "virtual override".into(),
|
||||||
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
|
insert_text: Some("pub virtual $1 $2() override$3\n{\n\t$4\n}".into()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
sort_text: Some("0000".into()),
|
sort_text: Some("0000".into()),
|
||||||
preselect: Some(true),
|
preselect: Some(true),
|
||||||
@@ -1652,7 +1663,8 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(curr_scope, Scope::Class) {
|
|
||||||
|
if matches!(curr_scope, Scope::Class | Scope::Struct) {
|
||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "field".into(),
|
label: "field".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
@@ -1682,7 +1694,7 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "variant".into(),
|
label: "variant".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
insert_text: Some("$1,".into()),
|
insert_text: Some("$1;".into()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
sort_text: Some("0000".into()),
|
sort_text: Some("0000".into()),
|
||||||
preselect: Some(true),
|
preselect: Some(true),
|
||||||
@@ -1692,7 +1704,7 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "tuple variant".into(),
|
label: "tuple variant".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
insert_text: Some("$1($2),".into()),
|
insert_text: Some("$1($2);".into()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
sort_text: Some("0000".into()),
|
sort_text: Some("0000".into()),
|
||||||
preselect: Some(true),
|
preselect: Some(true),
|
||||||
@@ -1702,7 +1714,7 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec<Completion
|
|||||||
items.push(CompletionItem {
|
items.push(CompletionItem {
|
||||||
label: "struct variant".into(),
|
label: "struct variant".into(),
|
||||||
kind: Some(CompletionItemKind::SNIPPET),
|
kind: Some(CompletionItemKind::SNIPPET),
|
||||||
insert_text: Some("$1\n{\n\t$0\n},".into()),
|
insert_text: Some("$1\n{\n\t$0\n};".into()),
|
||||||
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
insert_text_format: Some(InsertTextFormat::SNIPPET),
|
||||||
sort_text: Some("0000".into()),
|
sort_text: Some("0000".into()),
|
||||||
preselect: Some(true),
|
preselect: Some(true),
|
||||||
@@ -2024,10 +2036,7 @@ fn compute_mod_decls(
|
|||||||
let source = rope.to_string();
|
let source = rope.to_string();
|
||||||
parse_module(&source).ok().flatten().map(|(_, name)| name.0)
|
parse_module(&source).ok().flatten().map(|(_, name)| name.0)
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| file.file_stem().and_then(|s| s.to_str().map(String::from)));
|
||||||
file.file_stem()
|
|
||||||
.and_then(|s| s.to_str().map(String::from))
|
|
||||||
});
|
|
||||||
if let Some(name) = mod_name {
|
if let Some(name) = mod_name {
|
||||||
mod_decl.push_str(&format!("pub mod {};\n", name));
|
mod_decl.push_str(&format!("pub mod {};\n", name));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub struct ClassProcessedData {
|
|||||||
items: Vec<ClassItem>,
|
items: Vec<ClassItem>,
|
||||||
methods: Vec<Spanned<FunctionDecl>>,
|
methods: Vec<Spanned<FunctionDecl>>,
|
||||||
v_table: Vec<Identifier>,
|
v_table: Vec<Identifier>,
|
||||||
override_v_table: HashMap<Override, Spanned<Vec<Identifier>>>,
|
override_v_table: HashMap<Override, Spanned<Vec<(Identifier, bool)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassProcessedData {
|
impl ClassProcessedData {
|
||||||
@@ -51,7 +51,7 @@ impl ClassProcessedData {
|
|||||||
if matches!(method.item.visibility, Visibility::Public) {
|
if matches!(method.item.visibility, Visibility::Public) {
|
||||||
match &method.item.is_override {
|
match &method.item.is_override {
|
||||||
None => {
|
None => {
|
||||||
if method.item.self_param.is_some() {
|
if method.item.is_virtual && method.item.self_param.is_some() {
|
||||||
v_table.push(method.item.name.clone());
|
v_table.push(method.item.name.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ impl ClassProcessedData {
|
|||||||
item: Vec::new(),
|
item: Vec::new(),
|
||||||
})
|
})
|
||||||
.item
|
.item
|
||||||
.push(method.item.name.clone());
|
.push((method.item.name.clone(), method.item.is_virtual));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,13 +191,13 @@ impl ClassProcessedData {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap_or(self.inherits.as_ref().unwrap())
|
.unwrap_or(self.inherits.as_ref().unwrap())
|
||||||
.get_rust();
|
.get_rust();
|
||||||
for method_ident in &overriden_method_idents.item {
|
for (method_ident, is_virtual) in &overriden_method_idents.item {
|
||||||
cg.add_indentedln(&format!(
|
cg.add_indentedln(&format!(
|
||||||
"table[{}::__FN_{}] = {}::__m_{} as *const std::ffi::c_void;",
|
"table[{}::__FN_{}] = {}::{} as *const std::ffi::c_void;",
|
||||||
base_class_path,
|
base_class_path,
|
||||||
method_ident.0.to_uppercase(),
|
method_ident.0.to_uppercase(),
|
||||||
self.self_path.get_rust(),
|
self.self_path.get_rust(),
|
||||||
method_ident.get_rust()
|
get_virtual_name(method_ident, *is_virtual)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,6 +380,7 @@ impl ClassProcessedData {
|
|||||||
column: constructor.column,
|
column: constructor.column,
|
||||||
item: FunctionDecl {
|
item: FunctionDecl {
|
||||||
visibility: constructor.item.visibility.clone(),
|
visibility: constructor.item.visibility.clone(),
|
||||||
|
is_virtual: false,
|
||||||
is_override: None,
|
is_override: None,
|
||||||
name: Identifier(String::from("constructor")),
|
name: Identifier(String::from("constructor")),
|
||||||
generics: constructor.item.generics.clone(),
|
generics: constructor.item.generics.clone(),
|
||||||
@@ -396,7 +397,7 @@ impl ClassProcessedData {
|
|||||||
for method in &self.methods {
|
for method in &self.methods {
|
||||||
match method.item.visibility {
|
match method.item.visibility {
|
||||||
Visibility::Public => {
|
Visibility::Public => {
|
||||||
if method.item.self_param.is_some() {
|
if method.item.is_virtual && method.item.self_param.is_some() {
|
||||||
if method.item.is_override.is_none() {
|
if method.item.is_override.is_none() {
|
||||||
gen_method_point(&method.item, ctx, cg);
|
gen_method_point(&method.item, ctx, cg);
|
||||||
}
|
}
|
||||||
@@ -617,3 +618,11 @@ pub fn get_type_from_path(path: &ExprPath) -> TypeExpr {
|
|||||||
path.0.last().unwrap().generics.clone(),
|
path.0.last().unwrap().generics.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_virtual_name(name: &Identifier, is_virtual: bool) -> String {
|
||||||
|
if is_virtual {
|
||||||
|
format!("__m_{}", name.get_rust())
|
||||||
|
} else {
|
||||||
|
name.get_rust()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -107,12 +107,13 @@ pub struct Override(pub Option<ExprPath>);
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct FunctionDecl {
|
pub struct FunctionDecl {
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
pub is_override: Option<Override>,
|
pub is_virtual: bool,
|
||||||
|
pub return_type: Option<TypeExpr>,
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
pub generics: GenericsDecl,
|
pub generics: GenericsDecl,
|
||||||
pub self_param: Option<(bool, Option<Identifier>, bool)>,
|
pub self_param: Option<(bool, Option<Identifier>, bool)>,
|
||||||
pub params: ParamList,
|
pub params: ParamList,
|
||||||
pub return_type: Option<TypeExpr>,
|
pub is_override: Option<Override>,
|
||||||
pub body: Option<Block>,
|
pub body: Option<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +130,6 @@ pub struct FieldDecl {
|
|||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
pub type_: TypeExpr,
|
pub type_: TypeExpr,
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
// pub tuple_names: Vec<Identifier>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ keyword = {
|
|||||||
| "override"
|
| "override"
|
||||||
| "const"
|
| "const"
|
||||||
| "type"
|
| "type"
|
||||||
|
| "virtual"
|
||||||
}
|
}
|
||||||
|
|
||||||
identifier = @{
|
identifier = @{
|
||||||
@@ -373,10 +374,12 @@ trait_decl = {
|
|||||||
// FUNCTIONS
|
// FUNCTIONS
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
|
virtual_kw = { "virtual" }
|
||||||
|
|
||||||
override_kw = { "override" ~ ("(" ~ expr_path ~ ")")? }
|
override_kw = { "override" ~ ("(" ~ expr_path ~ ")")? }
|
||||||
|
|
||||||
function_decl = {
|
function_decl = {
|
||||||
visibility? ~ ("void" | type_expr) ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ override_kw? ~ (block | semicolon)
|
visibility? ~ virtual_kw? ~ ("void" | type_expr) ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ override_kw? ~ (block | semicolon)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
|||||||
let mut inner = pair.into_inner();
|
let mut inner = pair.into_inner();
|
||||||
let visibility = Visibility::try_from(&mut inner)?;
|
let visibility = Visibility::try_from(&mut inner)?;
|
||||||
|
|
||||||
|
let is_virtual = listen_rule(&mut inner, Rule::virtual_kw);
|
||||||
|
|
||||||
let return_type = consume_rule(&mut inner, Rule::type_expr)
|
let return_type = consume_rule(&mut inner, Rule::type_expr)
|
||||||
.map(TypeExpr::try_from)
|
.map(TypeExpr::try_from)
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
@@ -45,12 +47,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for FunctionDecl {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
is_override: is_override,
|
is_virtual: is_virtual,
|
||||||
return_type: return_type,
|
return_type: return_type,
|
||||||
name: name,
|
name: name,
|
||||||
generics: generics,
|
generics: generics,
|
||||||
self_param: self_param,
|
self_param: self_param,
|
||||||
params: params,
|
params: params,
|
||||||
|
is_override: is_override,
|
||||||
body: body,
|
body: body,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -102,6 +102,28 @@ pub fn check_class_semantics<'a>(top_level: &TopLevel) -> Result<(), Vec<Semanti
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else if let TopLevelKind::FunctionDecl(decl) = &top_level.0.item {
|
||||||
|
if decl.is_virtual && decl.is_override.is_some() {
|
||||||
|
Err(vec![SemanticError {
|
||||||
|
line: top_level.0.line,
|
||||||
|
column: top_level.0.column,
|
||||||
|
error_message: "virtual and override are only used in classes".to_string(),
|
||||||
|
}])
|
||||||
|
} else if decl.is_virtual {
|
||||||
|
Err(vec![SemanticError {
|
||||||
|
line: top_level.0.line,
|
||||||
|
column: top_level.0.column,
|
||||||
|
error_message: "virtual is only used in classes".to_string(),
|
||||||
|
}])
|
||||||
|
} else if decl.is_override.is_some() {
|
||||||
|
Err(vec![SemanticError {
|
||||||
|
line: top_level.0.line,
|
||||||
|
column: top_level.0.column,
|
||||||
|
error_message: "override is only used in classes".to_string(),
|
||||||
|
}])
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
pub module class_test;
|
pub module class_test;
|
||||||
|
|
||||||
|
pub enum AnimalType {
|
||||||
|
Mammal;
|
||||||
|
}
|
||||||
|
|
||||||
pub class Animal
|
pub class Animal
|
||||||
{
|
{
|
||||||
pub String name;
|
pub String name;
|
||||||
@@ -9,7 +13,11 @@ pub class Animal
|
|||||||
self.name = "Rex".to_string();
|
self.name = "Rex".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub String speak(&self)
|
pub virtual AnimalType get_animal_type(&self) {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub virtual String speak(&self)
|
||||||
{
|
{
|
||||||
"Unknown".to_string()
|
"Unknown".to_string()
|
||||||
}
|
}
|
||||||
@@ -31,6 +39,11 @@ pub class Mammal : Animal
|
|||||||
super = Super::new();
|
super = Super::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// override without a target assumes current super
|
||||||
|
pub AnimalType get_animal_type(&self) override {
|
||||||
|
AnimalType::Mammal
|
||||||
|
}
|
||||||
|
|
||||||
pub void args_test(&self, i32 x, str& y)
|
pub void args_test(&self, i32 x, str& y)
|
||||||
{
|
{
|
||||||
assert_eq!(x, 10);
|
assert_eq!(x, 10);
|
||||||
@@ -124,6 +137,7 @@ pub void run_tests()
|
|||||||
let dawg = Dog::new();
|
let dawg = Dog::new();
|
||||||
dawg.args_test(10, "hello");
|
dawg.args_test(10, "hello");
|
||||||
dawg.test_speak();
|
dawg.test_speak();
|
||||||
|
dawg.get_animal_type();
|
||||||
assert_eq!(format!("{dawg}"), "🐾 Rex");
|
assert_eq!(format!("{dawg}"), "🐾 Rex");
|
||||||
test_class_no_inheritance();
|
test_class_no_inheritance();
|
||||||
test_class_field_default();
|
test_class_field_default();
|
||||||
|
|||||||
Reference in New Issue
Block a user