Compare commits
No commits in common. "86fcbb494bd17ae948f82361e0c463e8060a5297" and "fa13697596666aeb153fd80cc3cd2fc7d57ff975" have entirely different histories.
86fcbb494b
...
fa13697596
@ -22,10 +22,6 @@ impl AssignStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destination(&self) -> &Expression {
|
|
||||||
&self.destination
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
pub fn gather_declared_names(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
|
|||||||
@ -1,30 +1,22 @@
|
|||||||
use crate::ast::constructor::Constructor;
|
use crate::ast::constructor::Constructor;
|
||||||
use crate::ast::expression::Expression;
|
|
||||||
use crate::ast::field::Field;
|
use crate::ast::field::Field;
|
||||||
use crate::ast::fqn_context::FqnContext;
|
use crate::ast::fqn_context::FqnContext;
|
||||||
use crate::ast::fqn_util::fqn_parts_to_string;
|
use crate::ast::fqn_util::fqn_parts_to_string;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::generic_parameter::GenericParameter;
|
|
||||||
use crate::ast::statement::Statement;
|
|
||||||
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
||||||
use crate::ir::ir_class::{IrClass, IrField};
|
use crate::ir::ir_class::{IrClass, IrField};
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::maybe_return_diagnostics;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
use std::process::id;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
generic_parameters: Vec<GenericParameter>,
|
|
||||||
constructor: Option<Constructor>,
|
constructor: Option<Constructor>,
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
@ -35,7 +27,6 @@ impl Class {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
declared_name: &str,
|
declared_name: &str,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
generic_parameters: Vec<GenericParameter>,
|
|
||||||
constructor: Option<Constructor>,
|
constructor: Option<Constructor>,
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
functions: Vec<Function>,
|
functions: Vec<Function>,
|
||||||
@ -43,7 +34,6 @@ impl Class {
|
|||||||
Class {
|
Class {
|
||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
generic_parameters,
|
|
||||||
constructor,
|
constructor,
|
||||||
fields,
|
fields,
|
||||||
functions,
|
functions,
|
||||||
@ -97,51 +87,18 @@ impl Class {
|
|||||||
// 2. push scope
|
// 2. push scope
|
||||||
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
symbol_table.push_class_scope(&format!("class_scope({})", self.declared_name));
|
||||||
|
|
||||||
// 3a. gather generic parameters
|
// 3. gather fields
|
||||||
let mut generic_parameter_symbols: Vec<Rc<RefCell<GenericParameterSymbol>>> = vec![];
|
let fields_diagnostics: Vec<Diagnostic> = self
|
||||||
let mut generic_parameter_diagnostics: Vec<Diagnostic> = vec![];
|
.fields
|
||||||
for generic_parameter in &mut self.generic_parameters {
|
.iter_mut()
|
||||||
match generic_parameter.gather_declared_names(symbol_table) {
|
.enumerate()
|
||||||
Ok(generic_parameter_symbol) => {
|
.map(|(field_index, field)| field.gather_declared_names(symbol_table, field_index))
|
||||||
generic_parameter_symbols.push(generic_parameter_symbol);
|
.filter_map(Result::err)
|
||||||
}
|
.flatten()
|
||||||
Err(mut d) => {
|
.collect();
|
||||||
generic_parameter_diagnostics.append(&mut d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maybe_return_diagnostics!(generic_parameter_diagnostics);
|
|
||||||
// save generics to class symbol
|
|
||||||
self.class_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_generic_parameters(generic_parameter_symbols);
|
|
||||||
|
|
||||||
// 3b. gather fields
|
|
||||||
let mut field_symbols: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> = HashMap::new();
|
|
||||||
let mut fields_diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
for (index, field) in self.fields.iter_mut().enumerate() {
|
|
||||||
match field.gather_declared_names(symbol_table, index) {
|
|
||||||
Ok(field_symbol) => {
|
|
||||||
field_symbols.insert(field.declared_name_owned(), field_symbol);
|
|
||||||
}
|
|
||||||
Err(mut d) => {
|
|
||||||
fields_diagnostics.append(&mut d);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if !fields_diagnostics.is_empty() {
|
if !fields_diagnostics.is_empty() {
|
||||||
return Err(fields_diagnostics);
|
return Err(fields_diagnostics);
|
||||||
} else {
|
|
||||||
self.class_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_fields(field_symbols);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. gather constructor
|
// 4. gather constructor
|
||||||
@ -185,17 +142,6 @@ impl Class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let generics_diagnostics: Vec<Diagnostic> = self
|
|
||||||
.generic_parameters
|
|
||||||
.iter_mut()
|
|
||||||
.map(|generic_parameter| {
|
|
||||||
generic_parameter.check_name_usages(symbol_table, self.class_symbol.as_ref())
|
|
||||||
})
|
|
||||||
.filter_map(Result::err)
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
maybe_return_diagnostics!(generics_diagnostics);
|
|
||||||
|
|
||||||
self.constructor
|
self.constructor
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|constructor| {
|
.map(|constructor| {
|
||||||
@ -287,23 +233,10 @@ impl Class {
|
|||||||
if let Some(constructor) = &self.constructor {
|
if let Some(constructor) = &self.constructor {
|
||||||
for statement in constructor.statements() {
|
for statement in constructor.statements() {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::Assign(assign_statement) => match assign_statement.destination() {
|
_ => {
|
||||||
Expression::Identifier(identifier) => {
|
// no-op for now, because we don't yet have assign statements
|
||||||
if self
|
|
||||||
.class_symbol
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.borrow()
|
|
||||||
.fields()
|
|
||||||
.contains_key(identifier.name())
|
|
||||||
{
|
|
||||||
initialized_field_names.insert(identifier.name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Found a non L Value assign lhs"),
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ impl Field {
|
|||||||
&mut self,
|
&mut self,
|
||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
field_index: usize,
|
field_index: usize,
|
||||||
) -> Result<Rc<RefCell<FieldSymbol>>, Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
// 1. insert field symbol
|
// 1. insert field symbol
|
||||||
let to_insert = FieldSymbol::new(
|
let to_insert = FieldSymbol::new(
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
@ -82,7 +82,6 @@ impl Field {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// save for later
|
// save for later
|
||||||
let to_return = field_symbol.clone();
|
|
||||||
self.field_symbol = Some(field_symbol);
|
self.field_symbol = Some(field_symbol);
|
||||||
|
|
||||||
// set field index on symbol
|
// set field index on symbol
|
||||||
@ -101,7 +100,7 @@ impl Field {
|
|||||||
initializer.gather_declared_names(symbol_table)?;
|
initializer.gather_declared_names(symbol_table)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(to_return)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn check_name_usages(
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use crate::ast::parameter::Parameter;
|
|||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::type_use::TypeUse;
|
use crate::ast::type_use::TypeUse;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::handle_diagnostics;
|
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
use crate::ir::ir_parameter_or_variable::IrParameterOrVariable;
|
||||||
@ -110,7 +109,7 @@ impl Function {
|
|||||||
Parameter::new(
|
Parameter::new(
|
||||||
"self",
|
"self",
|
||||||
SourceRange::new(0, 0),
|
SourceRange::new(0, 0),
|
||||||
TypeUse::new("Self", SourceRange::new(0, 0), vec![]),
|
TypeUse::new("Self", SourceRange::new(0, 0)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -239,11 +238,6 @@ impl Function {
|
|||||||
let return_type_info = function_symbol.borrow().return_type_info().clone();
|
let return_type_info = function_symbol.borrow().return_type_info().clone();
|
||||||
let statements_len = self.statements.len();
|
let statements_len = self.statements.len();
|
||||||
|
|
||||||
// return type
|
|
||||||
if let Some(type_use) = &mut self.return_type {
|
|
||||||
handle_diagnostics!(type_use.type_check(symbol_table), diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
diagnostics.append(
|
diagnostics.append(
|
||||||
&mut self
|
&mut self
|
||||||
|
|||||||
@ -1,120 +0,0 @@
|
|||||||
use crate::ast::type_use::TypeUse;
|
|
||||||
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
|
||||||
use crate::error_codes::SYMBOL_ALREADY_DECLARED;
|
|
||||||
use crate::source_range::SourceRange;
|
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
|
||||||
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct GenericParameter {
|
|
||||||
declared_name: Rc<str>,
|
|
||||||
declared_name_source_range: SourceRange,
|
|
||||||
extends: Vec<TypeUse>,
|
|
||||||
generic_parameter_symbol: Option<Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GenericParameter {
|
|
||||||
pub fn new(
|
|
||||||
declared_name: &str,
|
|
||||||
declared_name_source_range: SourceRange,
|
|
||||||
extends: Vec<TypeUse>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
declared_name: declared_name.into(),
|
|
||||||
declared_name_source_range,
|
|
||||||
extends,
|
|
||||||
generic_parameter_symbol: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gather_declared_names(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &mut SymbolTable,
|
|
||||||
) -> Result<Rc<RefCell<GenericParameterSymbol>>, Vec<Diagnostic>> {
|
|
||||||
// insert symbol
|
|
||||||
let to_insert =
|
|
||||||
GenericParameterSymbol::new(&self.declared_name, &self.declared_name_source_range);
|
|
||||||
let to_return = match symbol_table.insert_generic_parameter_symbol(to_insert) {
|
|
||||||
Ok(generic_parameter_symbol) => generic_parameter_symbol,
|
|
||||||
Err(symbol_insert_error) => {
|
|
||||||
return match symbol_insert_error {
|
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
|
||||||
let already_declared_symbol = already_declared.symbol().borrow();
|
|
||||||
let already_declared_source_range =
|
|
||||||
already_declared_symbol.declared_name_source_range();
|
|
||||||
let diagnostic = Diagnostic::new(
|
|
||||||
&format!("Symbol {} already declared in scope.", self.declared_name),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!())
|
|
||||||
.with_error_code(SYMBOL_ALREADY_DECLARED)
|
|
||||||
.with_secondary_labels(&[SecondaryLabel::new(
|
|
||||||
already_declared_source_range.start(),
|
|
||||||
already_declared_source_range.end(),
|
|
||||||
Some("Symbol already declared here.".to_string()),
|
|
||||||
)]);
|
|
||||||
Err(vec![diagnostic])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// save param symbol
|
|
||||||
self.generic_parameter_symbol = Some(to_return.clone());
|
|
||||||
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
for type_use in &mut self.extends {
|
|
||||||
handle_diagnostics!(type_use.gather_declared_names(symbol_table), diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(to_return)
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_name_usages(
|
|
||||||
&mut self,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
// check the extends type uses
|
|
||||||
for type_use in &mut self.extends {
|
|
||||||
handle_diagnostics!(
|
|
||||||
type_use.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
// now that each extends type use has type info, set the type infos on the generic parameter
|
|
||||||
let extends_type_infos = self
|
|
||||||
.extends
|
|
||||||
.iter()
|
|
||||||
.map(|type_use| type_use.type_info().clone())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
self.generic_parameter_symbol
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.set_extends(extends_type_infos);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
// check extends type uses
|
|
||||||
for type_use in &mut self.extends {
|
|
||||||
handle_diagnostics!(type_use.type_check(symbol_table), diagnostics);
|
|
||||||
}
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -13,7 +13,6 @@ pub mod fqn;
|
|||||||
pub mod fqn_context;
|
pub mod fqn_context;
|
||||||
pub mod fqn_util;
|
pub mod fqn_util;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod generic_parameter;
|
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod integer_literal;
|
pub mod integer_literal;
|
||||||
pub mod ir_builder;
|
pub mod ir_builder;
|
||||||
|
|||||||
@ -81,9 +81,8 @@ impl Parameter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.type_use.type_check(symbol_table)?;
|
Ok(()) // no-op for now
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameter_symbol(&self) -> &Rc<RefCell<ParameterSymbol>> {
|
pub fn parameter_symbol(&self) -> &Rc<RefCell<ParameterSymbol>> {
|
||||||
|
|||||||
@ -1,31 +1,23 @@
|
|||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::error_codes::INCORRECT_GENERIC_ARGUMENTS;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use crate::{diagnostics_result, handle_diagnostics, maybe_return_diagnostics};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct TypeUse {
|
pub struct TypeUse {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
generic_arguments: Vec<TypeUse>,
|
|
||||||
scope_id: Option<usize>,
|
scope_id: Option<usize>,
|
||||||
type_info: Option<TypeInfo>,
|
type_info: Option<TypeInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeUse {
|
impl TypeUse {
|
||||||
pub fn new(
|
pub fn new(declared_name: &str, declared_name_source_range: SourceRange) -> Self {
|
||||||
declared_name: &str,
|
|
||||||
declared_name_source_range: SourceRange,
|
|
||||||
generic_arguments: Vec<TypeUse>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
generic_arguments,
|
|
||||||
scope_id: None,
|
scope_id: None,
|
||||||
type_info: None,
|
type_info: None,
|
||||||
}
|
}
|
||||||
@ -40,14 +32,7 @@ impl TypeUse {
|
|||||||
symbol_table: &mut SymbolTable,
|
symbol_table: &mut SymbolTable,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
self.scope_id = Some(symbol_table.current_scope_id());
|
self.scope_id = Some(symbol_table.current_scope_id());
|
||||||
let mut inner_diagnostics: Vec<Diagnostic> = vec![];
|
Ok(())
|
||||||
for generic_argument in &mut self.generic_arguments {
|
|
||||||
handle_diagnostics!(
|
|
||||||
generic_argument.gather_declared_names(symbol_table),
|
|
||||||
inner_diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
diagnostics_result!(inner_diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_name_usages(
|
pub fn check_name_usages(
|
||||||
@ -55,8 +40,6 @@ impl TypeUse {
|
|||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
class_context: Option<&Rc<RefCell<ClassSymbol>>>,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
|
||||||
|
|
||||||
if let Some(type_info) = TypeInfo::from_declared_name(
|
if let Some(type_info) = TypeInfo::from_declared_name(
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
self.scope_id.unwrap(),
|
self.scope_id.unwrap(),
|
||||||
@ -64,114 +47,24 @@ impl TypeUse {
|
|||||||
class_context,
|
class_context,
|
||||||
) {
|
) {
|
||||||
self.type_info = Some(type_info);
|
self.type_info = Some(type_info);
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let diagnostic = Diagnostic::new(
|
Err(vec![
|
||||||
|
Diagnostic::new(
|
||||||
&format!("Unable to resolve symbol {}", self.declared_name),
|
&format!("Unable to resolve symbol {}", self.declared_name),
|
||||||
self.declared_name_source_range.start(),
|
self.declared_name_source_range.start(),
|
||||||
self.declared_name_source_range.end(),
|
self.declared_name_source_range.end(),
|
||||||
)
|
)
|
||||||
.with_reporter(file!(), line!());
|
.with_reporter(file!(), line!()),
|
||||||
diagnostics.push(diagnostic);
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
for generic_argument in &mut self.generic_arguments {
|
|
||||||
handle_diagnostics!(
|
|
||||||
generic_argument.check_name_usages(symbol_table, class_context),
|
|
||||||
diagnostics
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
pub fn type_check(&mut self, _symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
Ok(()) // no-op, for now
|
||||||
|
|
||||||
match self.type_info() {
|
|
||||||
TypeInfo::ClassInstance(class_symbol) => {
|
|
||||||
// check number of params/args match
|
|
||||||
let borrowed_class_symbol = class_symbol.borrow();
|
|
||||||
let generic_parameters = borrowed_class_symbol.generic_parameters();
|
|
||||||
if generic_parameters.len() != self.generic_arguments.len() {
|
|
||||||
let diagnostic = Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Expected {} generic arguments; found {}.",
|
|
||||||
generic_parameters.len(),
|
|
||||||
self.generic_arguments.len()
|
|
||||||
),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!())
|
|
||||||
.with_error_code(INCORRECT_GENERIC_ARGUMENTS);
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
maybe_return_diagnostics!(diagnostics);
|
|
||||||
|
|
||||||
// check that each arg is assignable to the param's extends
|
|
||||||
for i in 0..self.generic_arguments.len() {
|
|
||||||
let generic_parameter_symbol = generic_parameters[i].borrow();
|
|
||||||
if generic_parameter_symbol.extends().len() > 0 {
|
|
||||||
unimplemented!("Generic extends not implemented yet.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// cannot extend a non-class type (except for Any)
|
|
||||||
if self.generic_arguments.len() > 0 {
|
|
||||||
let diagnostic = Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Type {} does not accept generic arguments.",
|
|
||||||
self.type_info()
|
|
||||||
),
|
|
||||||
self.declared_name_source_range.start(),
|
|
||||||
self.declared_name_source_range.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!())
|
|
||||||
.with_error_code(INCORRECT_GENERIC_ARGUMENTS);
|
|
||||||
diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// recurse on generic arguments
|
|
||||||
for generic_argument in &mut self.generic_arguments {
|
|
||||||
handle_diagnostics!(generic_argument.type_check(_symbol_table), diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics_result!(diagnostics)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
self.type_info.as_ref().unwrap()
|
self.type_info.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::diagnostic::Diagnostic;
|
|
||||||
use crate::parser::parse_compilation_unit;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn type_check_generics() -> Result<(), Vec<Diagnostic>> {
|
|
||||||
let mut compilation_unit = parse_compilation_unit(
|
|
||||||
"
|
|
||||||
class Foo<T>
|
|
||||||
ctor(t: T) end
|
|
||||||
end
|
|
||||||
|
|
||||||
fn useFoo(foo: Foo<String>) end
|
|
||||||
",
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
|
||||||
|
|
||||||
compilation_unit.gather_declared_names(&mut symbol_table)?;
|
|
||||||
compilation_unit.check_name_usages(&mut symbol_table)?;
|
|
||||||
compilation_unit.type_check(&mut symbol_table)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
pub type ErrorCode = usize;
|
pub type ErrorCode = usize;
|
||||||
|
|
||||||
pub const SYMBOL_ALREADY_DECLARED: ErrorCode = 14;
|
|
||||||
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
pub const BINARY_INCOMPATIBLE_TYPES: ErrorCode = 15;
|
||||||
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
|
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
|
||||||
pub const ASSIGN_NO_L_VALUE: ErrorCode = 17;
|
pub const ASSIGN_NO_L_VALUE: ErrorCode = 17;
|
||||||
pub const ASSIGN_LHS_IMMUTABLE: ErrorCode = 18;
|
pub const ASSIGN_LHS_IMMUTABLE: ErrorCode = 18;
|
||||||
pub const INCORRECT_GENERIC_ARGUMENTS: ErrorCode = 19;
|
|
||||||
pub const GENERIC_ARGUMENT_TYPE_MISMATCH: ErrorCode = 20;
|
|
||||||
|
|||||||
@ -54,7 +54,6 @@ impl IrField {
|
|||||||
TypeInfo::ClassInstance(class_symbol) => VmTypeInfo::ClassInstance(
|
TypeInfo::ClassInstance(class_symbol) => VmTypeInfo::ClassInstance(
|
||||||
fqn_parts_to_string(class_symbol.borrow().fqn_parts()).into(),
|
fqn_parts_to_string(class_symbol.borrow().fqn_parts()).into(),
|
||||||
),
|
),
|
||||||
TypeInfo::GenericType(_) => VmTypeInfo::Any,
|
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@ -54,6 +54,10 @@ impl<'a> Lexer<'a> {
|
|||||||
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
Token::new(self.position, self.position + 1, TokenKind::Modulo)
|
||||||
} else if chunk.starts_with("+") {
|
} else if chunk.starts_with("+") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
||||||
|
} else if chunk.starts_with("<<") {
|
||||||
|
Token::new(self.position, self.position + 2, TokenKind::LeftShift)
|
||||||
|
} else if chunk.starts_with(">>") {
|
||||||
|
Token::new(self.position, self.position + 2, TokenKind::RightShift)
|
||||||
} else if chunk.starts_with("&") {
|
} else if chunk.starts_with("&") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
Token::new(self.position, self.position + 1, TokenKind::Ampersand)
|
||||||
} else if chunk.starts_with("^") {
|
} else if chunk.starts_with("^") {
|
||||||
@ -68,14 +72,6 @@ impl<'a> Lexer<'a> {
|
|||||||
Token::new(self.position, self.position + 1, TokenKind::Colon)
|
Token::new(self.position, self.position + 1, TokenKind::Colon)
|
||||||
} else if chunk.starts_with(".") {
|
} else if chunk.starts_with(".") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Dot)
|
Token::new(self.position, self.position + 1, TokenKind::Dot)
|
||||||
} else if chunk.starts_with("[") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::LeftSquare)
|
|
||||||
} else if chunk.starts_with("]") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::RightSquare)
|
|
||||||
} else if chunk.starts_with("<") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Lt)
|
|
||||||
} else if chunk.starts_with(">") {
|
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Gt)
|
|
||||||
} else {
|
} else {
|
||||||
// more than one char token
|
// more than one char token
|
||||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use crate::ast::expression_statement::ExpressionStatement;
|
|||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::field::Field;
|
use crate::ast::field::Field;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::ast::generic_parameter::GenericParameter;
|
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
@ -57,12 +56,6 @@ macro_rules! matches_statement_first {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! matches_type_use_first {
|
|
||||||
( $token_kind: expr ) => {
|
|
||||||
matches!($token_kind, TokenKind::LeftSquare | TokenKind::Identifier)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a> {
|
||||||
input: &'a str,
|
input: &'a str,
|
||||||
lexer: Lexer<'a>,
|
lexer: Lexer<'a>,
|
||||||
@ -170,26 +163,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_position_advance(
|
|
||||||
&mut self,
|
|
||||||
token_kind: TokenKind,
|
|
||||||
start_position: usize,
|
|
||||||
) -> Result<Token, Vec<Diagnostic>> {
|
|
||||||
let matched = self.expect_advance(token_kind)?;
|
|
||||||
if matched.start() == start_position {
|
|
||||||
Ok(matched)
|
|
||||||
} else {
|
|
||||||
Err(vec![
|
|
||||||
Diagnostic::new(
|
|
||||||
&format!("Expected {:?} but found {:?}", token_kind, matched.kind()),
|
|
||||||
matched.start(),
|
|
||||||
matched.end(),
|
|
||||||
)
|
|
||||||
.with_reporter(file!(), line!()),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn peek_current(&self, token_kind: TokenKind) -> bool {
|
fn peek_current(&self, token_kind: TokenKind) -> bool {
|
||||||
match &self.current {
|
match &self.current {
|
||||||
None => panic!("Unexpected end of input."),
|
None => panic!("Unexpected end of input."),
|
||||||
@ -414,7 +387,6 @@ impl<'a> Parser<'a> {
|
|||||||
fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
|
fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
|
||||||
self.expect_advance(TokenKind::Class)?;
|
self.expect_advance(TokenKind::Class)?;
|
||||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||||
let mut generic_parameters: Vec<GenericParameter> = vec![];
|
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
let mut functions = vec![];
|
let mut functions = vec![];
|
||||||
let mut maybe_constructor: Option<Constructor> = None;
|
let mut maybe_constructor: Option<Constructor> = None;
|
||||||
@ -445,14 +417,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
Err(mut ctor_diagnostics) => diagnostics.append(&mut ctor_diagnostics),
|
Err(mut ctor_diagnostics) => diagnostics.append(&mut ctor_diagnostics),
|
||||||
},
|
},
|
||||||
TokenKind::Lt => match self.generic_parameters() {
|
|
||||||
Ok(parsed_params) => {
|
|
||||||
generic_parameters = parsed_params;
|
|
||||||
}
|
|
||||||
Err(mut generic_parameters_diagnostics) => {
|
|
||||||
diagnostics.append(&mut generic_parameters_diagnostics);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -463,7 +427,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(Class::new(
|
Ok(Class::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
generic_parameters,
|
|
||||||
maybe_constructor,
|
maybe_constructor,
|
||||||
fields,
|
fields,
|
||||||
functions,
|
functions,
|
||||||
@ -514,95 +477,10 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
||||||
if self.current.is_some() {
|
|
||||||
let current = self.get_current();
|
|
||||||
return match current.kind() {
|
|
||||||
TokenKind::LeftSquare => {
|
|
||||||
self.advance(); // [
|
|
||||||
let inner_type_use = self.type_use()?;
|
|
||||||
self.expect_advance(TokenKind::RightSquare)?;
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
TokenKind::Identifier => {
|
|
||||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||||
let generic_arguments =
|
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Lt) {
|
|
||||||
self.advance(); // <
|
|
||||||
let generic_arguments = self.generic_arguments_list()?;
|
|
||||||
self.expect_advance(TokenKind::Gt)?; // >
|
|
||||||
generic_arguments
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
Ok(TypeUse::new(
|
Ok(TypeUse::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
||||||
generic_arguments,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => Err(vec![Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Expected LeftSquare or Identifier; found: {:?}",
|
|
||||||
current.kind()
|
|
||||||
),
|
|
||||||
current.start(),
|
|
||||||
current.end(),
|
|
||||||
)]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(vec![Diagnostic::new(
|
|
||||||
"Expected LeftSquare or Identifier; found end of input.",
|
|
||||||
self.input.len(),
|
|
||||||
self.input.len(),
|
|
||||||
)])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_arguments_list(&mut self) -> Result<Vec<TypeUse>, Vec<Diagnostic>> {
|
|
||||||
let mut generic_arguments: Vec<TypeUse> = vec![];
|
|
||||||
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
|
||||||
generic_arguments.push(self.type_use()?);
|
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
|
||||||
self.advance(); // comma
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(generic_arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_parameters(&mut self) -> Result<Vec<GenericParameter>, Vec<Diagnostic>> {
|
|
||||||
self.expect_advance(TokenKind::Lt)?;
|
|
||||||
let mut parameters: Vec<GenericParameter> = vec![];
|
|
||||||
while self.current.is_some() && self.peek_current(TokenKind::Identifier) {
|
|
||||||
parameters.push(self.generic_parameter()?);
|
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Plus) {
|
|
||||||
self.advance(); // +
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.expect_advance(TokenKind::Gt)?;
|
|
||||||
Ok(parameters)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_parameter(&mut self) -> Result<GenericParameter, Vec<Diagnostic>> {
|
|
||||||
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
|
||||||
let mut extends_list: Vec<TypeUse> = vec![];
|
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Colon) {
|
|
||||||
self.advance(); // :
|
|
||||||
while self.current.is_some() && matches_type_use_first!(self.get_current().kind()) {
|
|
||||||
extends_list.push(self.type_use()?);
|
|
||||||
if self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
|
||||||
self.advance(); // ,
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(GenericParameter::new(
|
|
||||||
self.token_text(&identifier),
|
|
||||||
SourceRange::new(identifier.start(), identifier.end()),
|
|
||||||
extends_list,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,10 +721,8 @@ impl<'a> Parser<'a> {
|
|||||||
while self.current.is_some() {
|
while self.current.is_some() {
|
||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Lt => {
|
TokenKind::LeftShift => {
|
||||||
let second_lt_start = current.start() + 1;
|
self.advance(); // left shift
|
||||||
self.advance(); // first <
|
|
||||||
self.expect_position_advance(TokenKind::Lt, second_lt_start)?; // second <
|
|
||||||
let rhs = self.additive_expression()?;
|
let rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -857,10 +733,8 @@ impl<'a> Parser<'a> {
|
|||||||
source_range,
|
source_range,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
TokenKind::Gt => {
|
TokenKind::RightShift => {
|
||||||
let second_gt_start = current.start() + 1;
|
self.advance(); // right shift
|
||||||
self.advance(); // first >
|
|
||||||
self.expect_position_advance(TokenKind::Gt, second_gt_start)?; // second gt
|
|
||||||
let rhs = self.additive_expression()?;
|
let rhs = self.additive_expression()?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
@ -1270,21 +1144,6 @@ mod smoke_tests {
|
|||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn array_generic_arg() {
|
|
||||||
smoke_test("fn main(args: Array<String>) end");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nested_generic_args() {
|
|
||||||
smoke_test("fn main(foo: Array<Bar<Foo>>) end");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn class_with_generic_param() {
|
|
||||||
smoke_test("class Foo<T> end");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -2,7 +2,6 @@ use crate::symbol::class_symbol::ClassSymbol;
|
|||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -10,7 +9,6 @@ use std::rc::Rc;
|
|||||||
pub struct ClassScope {
|
pub struct ClassScope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: usize,
|
parent_id: usize,
|
||||||
generic_parameter_symbols: HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
|
class_symbols: HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>>,
|
||||||
field_symbols: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
field_symbols: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
||||||
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
||||||
@ -22,7 +20,6 @@ impl ClassScope {
|
|||||||
Self {
|
Self {
|
||||||
debug_name: debug_name.into(),
|
debug_name: debug_name.into(),
|
||||||
parent_id,
|
parent_id,
|
||||||
generic_parameter_symbols: HashMap::new(),
|
|
||||||
class_symbols: HashMap::new(),
|
class_symbols: HashMap::new(),
|
||||||
field_symbols: HashMap::new(),
|
field_symbols: HashMap::new(),
|
||||||
function_symbols: HashMap::new(),
|
function_symbols: HashMap::new(),
|
||||||
@ -30,18 +27,6 @@ impl ClassScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generic_parameter_symbols(
|
|
||||||
&self,
|
|
||||||
) -> &HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>> {
|
|
||||||
&self.generic_parameter_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generic_parameter_symbols_mut(
|
|
||||||
&mut self,
|
|
||||||
) -> &mut HashMap<Rc<str>, Rc<RefCell<GenericParameterSymbol>>> {
|
|
||||||
&mut self.generic_parameter_symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
pub fn class_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<ClassSymbol>>> {
|
||||||
&self.class_symbols
|
&self.class_symbols
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ use crate::symbol::Symbol;
|
|||||||
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
use crate::symbol::constructor_symbol::ConstructorSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -13,7 +12,6 @@ pub struct ClassSymbol {
|
|||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
fqn_parts: Vec<Rc<str>>,
|
fqn_parts: Vec<Rc<str>>,
|
||||||
is_extern: bool,
|
is_extern: bool,
|
||||||
generic_parameters: Vec<Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
||||||
fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>,
|
||||||
functions: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
functions: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
|
||||||
@ -31,7 +29,6 @@ impl ClassSymbol {
|
|||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
fqn_parts,
|
fqn_parts,
|
||||||
is_extern,
|
is_extern,
|
||||||
generic_parameters: vec![],
|
|
||||||
constructor_symbol: None,
|
constructor_symbol: None,
|
||||||
fields: HashMap::new(),
|
fields: HashMap::new(),
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
@ -42,17 +39,6 @@ impl ClassSymbol {
|
|||||||
&self.fqn_parts
|
&self.fqn_parts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_generic_parameters(
|
|
||||||
&mut self,
|
|
||||||
generic_parameters: Vec<Rc<RefCell<GenericParameterSymbol>>>,
|
|
||||||
) {
|
|
||||||
self.generic_parameters = generic_parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generic_parameters(&self) -> &[Rc<RefCell<GenericParameterSymbol>>] {
|
|
||||||
&self.generic_parameters
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_constructor_symbol(
|
pub fn set_constructor_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
constructor_symbol: Option<Rc<RefCell<ConstructorSymbol>>>,
|
||||||
@ -60,10 +46,6 @@ impl ClassSymbol {
|
|||||||
self.constructor_symbol = constructor_symbol;
|
self.constructor_symbol = constructor_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fields(&mut self, fields: HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>>) {
|
|
||||||
self.fields = fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fields(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
pub fn fields(&self) -> &HashMap<Rc<str>, Rc<RefCell<FieldSymbol>>> {
|
||||||
&self.fields
|
&self.fields
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
use crate::source_range::SourceRange;
|
|
||||||
use crate::symbol::Symbol;
|
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct GenericParameterSymbol {
|
|
||||||
declared_name: Rc<str>,
|
|
||||||
declared_name_source_range: SourceRange,
|
|
||||||
extends: Option<Vec<TypeInfo>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GenericParameterSymbol {
|
|
||||||
pub fn new(declared_name: &Rc<str>, declared_name_source_range: &SourceRange) -> Self {
|
|
||||||
Self {
|
|
||||||
declared_name: declared_name.clone(),
|
|
||||||
declared_name_source_range: declared_name_source_range.clone(),
|
|
||||||
extends: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_extends(&mut self, extends: Vec<TypeInfo>) {
|
|
||||||
self.extends = Some(extends);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extends(&self) -> &[TypeInfo] {
|
|
||||||
self.extends.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Symbol for GenericParameterSymbol {
|
|
||||||
fn declared_name(&self) -> &str {
|
|
||||||
&self.declared_name
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_owned(&self) -> Rc<str> {
|
|
||||||
self.declared_name.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn declared_name_source_range(&self) -> &SourceRange {
|
|
||||||
&self.declared_name_source_range
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,7 +7,6 @@ pub mod constructor_symbol;
|
|||||||
pub mod expressible_symbol;
|
pub mod expressible_symbol;
|
||||||
pub mod field_symbol;
|
pub mod field_symbol;
|
||||||
pub mod function_symbol;
|
pub mod function_symbol;
|
||||||
pub mod generic_parameter_symbol;
|
|
||||||
pub mod parameter_symbol;
|
pub mod parameter_symbol;
|
||||||
pub mod type_symbol;
|
pub mod type_symbol;
|
||||||
pub mod variable_symbol;
|
pub mod variable_symbol;
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum TypeSymbol {
|
pub enum TypeSymbol {
|
||||||
Class(Rc<RefCell<ClassSymbol>>),
|
Class(Rc<RefCell<ClassSymbol>>),
|
||||||
GenericParameter(Rc<RefCell<GenericParameterSymbol>>),
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,19 +143,11 @@ fn find_type_symbol_in_module(module_scope: &ModuleScope, name: &str) -> Option<
|
|||||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
fn find_type_symbol_in_class(class_scope: &ClassScope, name: &str) -> Option<TypeSymbol> {
|
||||||
class_scope
|
class_scope
|
||||||
.class_symbols()
|
.class_symbols()
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
.map(|symbol| TypeSymbol::Class(symbol.clone()))
|
||||||
.or_else(|| {
|
|
||||||
class_scope
|
|
||||||
.generic_parameter_symbols()
|
|
||||||
.get(name)
|
|
||||||
.map(|generic_parameter_symbol| {
|
|
||||||
TypeSymbol::GenericParameter(generic_parameter_symbol.clone())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
pub fn find_type_symbol(scope: &Scope, name: &str) -> Option<TypeSymbol> {
|
||||||
|
|||||||
@ -11,13 +11,12 @@ use crate::symbol::constructor_symbol::ConstructorSymbol;
|
|||||||
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
use crate::symbol::expressible_symbol::ExpressibleSymbol;
|
||||||
use crate::symbol::field_symbol::FieldSymbol;
|
use crate::symbol::field_symbol::FieldSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use crate::symbol::parameter_symbol::ParameterSymbol;
|
use crate::symbol::parameter_symbol::ParameterSymbol;
|
||||||
use crate::symbol::type_symbol::TypeSymbol;
|
use crate::symbol::type_symbol::TypeSymbol;
|
||||||
use crate::symbol::variable_symbol::VariableSymbol;
|
use crate::symbol::variable_symbol::VariableSymbol;
|
||||||
use crate::symbol_table::helpers::{
|
use crate::symbol_table::helpers::{
|
||||||
find_expressible_symbol, find_in_block_by_name, find_in_class_by_name,
|
find_expressible_symbol, find_in_block_by_name, find_in_class_by_name,
|
||||||
find_in_function_by_name, find_in_module_by_name, find_type_symbol, find_type_symbol_in_class,
|
find_in_function_by_name, find_in_module_by_name, find_type_symbol,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -125,48 +124,6 @@ impl SymbolTable {
|
|||||||
Ok(to_return)
|
Ok(to_return)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_generic_parameter_symbol(
|
|
||||||
&mut self,
|
|
||||||
generic_parameter_symbol: GenericParameterSymbol,
|
|
||||||
) -> Result<Rc<RefCell<GenericParameterSymbol>>, SymbolInsertError> {
|
|
||||||
let maybe_already_inserted = match self.current_scope() {
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
find_type_symbol_in_class(class_scope, generic_parameter_symbol.declared_name())
|
|
||||||
}
|
|
||||||
_ => panic!("Attempt to insert GenericParameterSymbol in incompatible scope"),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(already_inserted) = maybe_already_inserted {
|
|
||||||
match already_inserted {
|
|
||||||
TypeSymbol::Class(class_symbol) => {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
class_symbol as Rc<RefCell<dyn Symbol>>,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
TypeSymbol::GenericParameter(generic_parameter_symbol) => {
|
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
|
||||||
generic_parameter_symbol as Rc<RefCell<dyn Symbol>>,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = generic_parameter_symbol.declared_name_owned();
|
|
||||||
let as_rc = Rc::new(RefCell::new(generic_parameter_symbol));
|
|
||||||
let to_return = as_rc.clone();
|
|
||||||
|
|
||||||
match self.current_scope_mut() {
|
|
||||||
Scope::Class(class_scope) => {
|
|
||||||
class_scope
|
|
||||||
.generic_parameter_symbols_mut()
|
|
||||||
.insert(name, as_rc);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(to_return)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_constructor_symbol(
|
pub fn insert_constructor_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
constructor_symbol: ConstructorSymbol,
|
constructor_symbol: ConstructorSymbol,
|
||||||
|
|||||||
@ -45,6 +45,8 @@ pub enum TokenKind {
|
|||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
Modulo,
|
Modulo,
|
||||||
|
LeftShift,
|
||||||
|
RightShift,
|
||||||
Ampersand,
|
Ampersand,
|
||||||
Caret,
|
Caret,
|
||||||
Bar,
|
Bar,
|
||||||
@ -54,8 +56,4 @@ pub enum TokenKind {
|
|||||||
Public,
|
Public,
|
||||||
Mut,
|
Mut,
|
||||||
Ctor,
|
Ctor,
|
||||||
LeftSquare,
|
|
||||||
RightSquare,
|
|
||||||
Lt,
|
|
||||||
Gt,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::symbol::Symbol;
|
use crate::symbol::Symbol;
|
||||||
use crate::symbol::class_symbol::ClassSymbol;
|
use crate::symbol::class_symbol::ClassSymbol;
|
||||||
use crate::symbol::function_symbol::FunctionSymbol;
|
use crate::symbol::function_symbol::FunctionSymbol;
|
||||||
use crate::symbol::generic_parameter_symbol::GenericParameterSymbol;
|
|
||||||
use crate::symbol::type_symbol::TypeSymbol;
|
use crate::symbol::type_symbol::TypeSymbol;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -16,7 +15,6 @@ pub enum TypeInfo {
|
|||||||
String,
|
String,
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<RefCell<FunctionSymbol>>),
|
||||||
ClassInstance(Rc<RefCell<ClassSymbol>>),
|
ClassInstance(Rc<RefCell<ClassSymbol>>),
|
||||||
GenericType(Rc<RefCell<GenericParameterSymbol>>),
|
|
||||||
Void,
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,9 +35,6 @@ impl Display for TypeInfo {
|
|||||||
TypeInfo::ClassInstance(class_symbol) => {
|
TypeInfo::ClassInstance(class_symbol) => {
|
||||||
write!(f, "{}", class_symbol.borrow().declared_name())
|
write!(f, "{}", class_symbol.borrow().declared_name())
|
||||||
}
|
}
|
||||||
TypeInfo::GenericType(generic_parameter_symbol) => {
|
|
||||||
write!(f, "{}", generic_parameter_symbol.borrow().declared_name())
|
|
||||||
}
|
|
||||||
TypeInfo::Void => write!(f, "Void"),
|
TypeInfo::Void => write!(f, "Void"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,9 +66,6 @@ impl TypeInfo {
|
|||||||
None => None,
|
None => None,
|
||||||
Some(type_symbol) => match type_symbol {
|
Some(type_symbol) => match type_symbol {
|
||||||
TypeSymbol::Class(class_symbol) => Some(TypeInfo::ClassInstance(class_symbol)),
|
TypeSymbol::Class(class_symbol) => Some(TypeInfo::ClassInstance(class_symbol)),
|
||||||
TypeSymbol::GenericParameter(generic_parameter_symbol) => {
|
|
||||||
Some(TypeInfo::GenericType(generic_parameter_symbol))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -103,14 +95,6 @@ impl TypeInfo {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeInfo::GenericType(generic_parameter_symbol) => {
|
|
||||||
if generic_parameter_symbol.borrow().extends().len() > 0 {
|
|
||||||
unimplemented!(
|
|
||||||
"Assigning to generic parameter type with extends type uses not yet supported."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
TypeInfo::Void => {
|
TypeInfo::Void => {
|
||||||
matches!(other, TypeInfo::Void)
|
matches!(other, TypeInfo::Void)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
use std::alloc::{Layout, alloc};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Array<T> {
|
|
||||||
header: ArrayHeader,
|
|
||||||
data: [T],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ArrayHeader {
|
|
||||||
length: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_array<T: Clone>(length: usize, init: T) -> Box<Array<T>> {
|
|
||||||
let (layout, data_base) = Layout::array::<T>(length)
|
|
||||||
.and_then(|data_layout| Layout::new::<ArrayHeader>().extend(data_layout))
|
|
||||||
.unwrap();
|
|
||||||
let ptr = unsafe { alloc(layout) };
|
|
||||||
if ptr.is_null() {
|
|
||||||
panic!("failed to allocate memory");
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
ptr.cast::<ArrayHeader>().write(ArrayHeader { length });
|
|
||||||
let data_ptr = ptr.add(data_base).cast::<T>();
|
|
||||||
for i in 0..length {
|
|
||||||
data_ptr.add(i).write(init.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
Box::from_raw(std::ptr::slice_from_raw_parts(ptr as *mut T, length) as *mut Array<T>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::vm::array::get_array;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn int_array() {
|
|
||||||
let int_array = get_array::<i32>(5, 0);
|
|
||||||
assert_eq!(int_array.data.len(), 5);
|
|
||||||
assert_eq!(int_array.header.length, 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -17,7 +17,6 @@ use std::collections::HashMap;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub mod array;
|
|
||||||
pub mod class;
|
pub mod class;
|
||||||
pub mod constant;
|
pub mod constant;
|
||||||
pub mod function;
|
pub mod function;
|
||||||
|
|||||||
@ -8,7 +8,6 @@ pub enum TypeInfo {
|
|||||||
Int,
|
Int,
|
||||||
Double,
|
Double,
|
||||||
String,
|
String,
|
||||||
Any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeInfo {
|
impl TypeInfo {
|
||||||
@ -37,7 +36,6 @@ impl TypeInfo {
|
|||||||
TypeInfo::String => {
|
TypeInfo::String => {
|
||||||
matches!(value, Value::String(_))
|
matches!(value, Value::String(_))
|
||||||
}
|
}
|
||||||
TypeInfo::Any => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -290,31 +290,6 @@ mod e2e_tests {
|
|||||||
assert_eq!(o.fields().len(), 1);
|
assert_eq!(o.fields().len(), 1);
|
||||||
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn see_what_happens() {
|
|
||||||
let context = prepare_context(
|
|
||||||
"
|
|
||||||
class Foo<T>
|
|
||||||
mut t: T
|
|
||||||
ctor(_t: T)
|
|
||||||
t = _t
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
fn main() -> Foo<Int>
|
|
||||||
Foo(42)
|
|
||||||
end
|
|
||||||
",
|
|
||||||
);
|
|
||||||
let result = get_result(&context, "main", &vec![]);
|
|
||||||
assert!(result.is_some());
|
|
||||||
let value = result.unwrap();
|
|
||||||
assert!(matches!(value, Value::Object(_)));
|
|
||||||
let o = value.unwrap_object().borrow();
|
|
||||||
assert_eq!(o.fields().len(), 1);
|
|
||||||
assert_eq!(o.fields()[0].unwrap_int(), 42);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
extern fn println(message: Any) -> Void
|
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
let n = 1 + 2 * 3 + 4
|
let n = 1 + 2 * 3 + 4
|
||||||
println(n)
|
println(n)
|
||||||
|
|||||||
5
examples/op_prec.dvm_ir
Normal file
5
examples/op_prec.dvm_ir
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
fn main() -> Void
|
||||||
|
$0 = 2 * 3
|
||||||
|
$1 = 1 + $0
|
||||||
|
$2 = $1 + 4
|
||||||
|
call std::core::println($2)
|
||||||
@ -1,40 +0,0 @@
|
|||||||
fn main(args: [String])
|
|
||||||
println(args[0])
|
|
||||||
end
|
|
||||||
|
|
||||||
int Index<T, I>
|
|
||||||
op [](i: I) -> T
|
|
||||||
end
|
|
||||||
|
|
||||||
int Slice<T> : Index<T, ISize>, Iterable<T>
|
|
||||||
length: ISize
|
|
||||||
|
|
||||||
def fn iter() -> Iterator<T>
|
|
||||||
let mut i = 0
|
|
||||||
{
|
|
||||||
if i < length then
|
|
||||||
i++
|
|
||||||
Some(self[i - 1])
|
|
||||||
else
|
|
||||||
None
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
int Iterator<T>
|
|
||||||
fn next() -> Option<T>
|
|
||||||
end
|
|
||||||
|
|
||||||
int Iterable<T>
|
|
||||||
fn iter() -> Iterator<T>
|
|
||||||
end
|
|
||||||
|
|
||||||
extern class Array<T> : Index<T, ISize>, Slice<T>
|
|
||||||
extern length: ISize
|
|
||||||
extern op [](i: ISize) -> T
|
|
||||||
end
|
|
||||||
|
|
||||||
int List<T> : Index<T, ISize>, Slice<T>
|
|
||||||
|
|
||||||
end
|
|
||||||
Loading…
Reference in New Issue
Block a user