Parsing/analyzing assign statements.
This commit is contained in:
parent
f7e8cef380
commit
7e613b1b90
@ -164,7 +164,7 @@ fn report_and_exit(
|
|||||||
.with_labels(secondary_labels);
|
.with_labels(secondary_labels);
|
||||||
|
|
||||||
if let Some(error_code) = diagnostic.error_code() {
|
if let Some(error_code) = diagnostic.error_code() {
|
||||||
csr_diagnostic = csr_diagnostic.with_code(format!("E{}", error_code));
|
csr_diagnostic = csr_diagnostic.with_code(format!("E{:04}", error_code));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((reporter_file, reporter_line)) = diagnostic.reporter() {
|
if let Some((reporter_file, reporter_line)) = diagnostic.reporter() {
|
||||||
|
|||||||
250
dmc-lib/src/ast/assign_statement.rs
Normal file
250
dmc-lib/src/ast/assign_statement.rs
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::diagnostic::{Diagnostic, SecondaryLabel};
|
||||||
|
use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
|
||||||
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
|
pub struct AssignStatement {
|
||||||
|
destination: Box<Expression>,
|
||||||
|
value: Box<Expression>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssignStatement {
|
||||||
|
pub fn new(destination: Expression, value: Expression) -> Self {
|
||||||
|
Self {
|
||||||
|
destination: destination.into(),
|
||||||
|
value: value.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
|
match self.value.gather_declared_names(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut value_diagnostics) => {
|
||||||
|
diagnostics.append(&mut value_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.destination.gather_declared_names(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut destination_diagnostics) => {
|
||||||
|
diagnostics.append(&mut destination_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
|
match self.value.check_name_usages(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut value_diagnostics) => {
|
||||||
|
diagnostics.append(&mut value_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.destination.check_name_usages(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut destination_diagnostics) => {
|
||||||
|
diagnostics.append(&mut destination_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||||
|
|
||||||
|
match self.value.type_check(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut value_diagnostics) => {
|
||||||
|
diagnostics.append(&mut value_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.destination.type_check(symbol_table) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(mut destination_diagnostics) => {
|
||||||
|
diagnostics.append(&mut destination_diagnostics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check destination is l value
|
||||||
|
match &*self.destination {
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
let expressible_symbol = identifier.expressible_symbol();
|
||||||
|
|
||||||
|
// check mutable
|
||||||
|
if !expressible_symbol.is_mut() {
|
||||||
|
let secondary_label = SecondaryLabel::new(
|
||||||
|
expressible_symbol.source_range().start(),
|
||||||
|
expressible_symbol.source_range().end(),
|
||||||
|
Some("Destination (declared here) is immutable.".to_string()),
|
||||||
|
);
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
"Destination is immutable and not re-assignable.",
|
||||||
|
self.destination.source_range().start(),
|
||||||
|
self.destination.source_range().end(),
|
||||||
|
)
|
||||||
|
.with_primary_label_message("Attempt to mutate immutable destination.")
|
||||||
|
.with_reporter(file!(), line!())
|
||||||
|
.with_error_code(ASSIGN_LHS_IMMUTABLE)
|
||||||
|
.with_secondary_labels(&[secondary_label]);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check assignable
|
||||||
|
let lhs_type = expressible_symbol.type_info();
|
||||||
|
let rhs_type = self.value.type_info();
|
||||||
|
if !lhs_type.is_assignable_from(rhs_type) {
|
||||||
|
let secondary_label = SecondaryLabel::new(
|
||||||
|
expressible_symbol.source_range().start(),
|
||||||
|
expressible_symbol.source_range().end(),
|
||||||
|
Some(format!(
|
||||||
|
"Destination declared here is of type {}.",
|
||||||
|
lhs_type
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
&format!(
|
||||||
|
"Mismatched types: right-hand side {} is not assignable to left {}.",
|
||||||
|
rhs_type, lhs_type
|
||||||
|
),
|
||||||
|
self.destination.source_range().start(),
|
||||||
|
self.value.source_range().end(),
|
||||||
|
)
|
||||||
|
.with_primary_label_message(&format!(
|
||||||
|
"Attempt to assign {} to {}.",
|
||||||
|
rhs_type, lhs_type
|
||||||
|
))
|
||||||
|
.with_error_code(ASSIGN_MISMATCHED_TYPES)
|
||||||
|
.with_reporter(file!(), line!())
|
||||||
|
.with_secondary_labels(&[secondary_label]);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
"Left-hand side of assign must be an L value.",
|
||||||
|
self.destination.source_range().start(),
|
||||||
|
self.destination.source_range().end(),
|
||||||
|
)
|
||||||
|
.with_primary_label_message("Must be L value.")
|
||||||
|
.with_reporter(file!(), line!())
|
||||||
|
.with_error_code(ASSIGN_NO_L_VALUE);
|
||||||
|
diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::error_codes::{ASSIGN_LHS_IMMUTABLE, ASSIGN_MISMATCHED_TYPES, ASSIGN_NO_L_VALUE};
|
||||||
|
use crate::parser::parse_compilation_unit;
|
||||||
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn finds_mismatched_types() {
|
||||||
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
|
"
|
||||||
|
fn main()
|
||||||
|
let mut x = 4
|
||||||
|
x = \"Hello\"
|
||||||
|
end
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
compilation_unit
|
||||||
|
.gather_declared_names(&mut symbol_table)
|
||||||
|
.unwrap();
|
||||||
|
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
||||||
|
match compilation_unit.type_check(&symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
panic!("Type check missed diagnostic.");
|
||||||
|
}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
assert_eq!(diagnostics.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
diagnostics[0].error_code().unwrap(),
|
||||||
|
ASSIGN_MISMATCHED_TYPES
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn finds_no_l_value() {
|
||||||
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
|
"
|
||||||
|
fn main()
|
||||||
|
42 = 42
|
||||||
|
end
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
compilation_unit
|
||||||
|
.gather_declared_names(&mut symbol_table)
|
||||||
|
.unwrap();
|
||||||
|
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
||||||
|
match compilation_unit.type_check(&symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
panic!("Type check missed diagnostic.");
|
||||||
|
}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
assert_eq!(diagnostics.len(), 1);
|
||||||
|
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_NO_L_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn finds_immutable_destination() {
|
||||||
|
let mut compilation_unit = parse_compilation_unit(
|
||||||
|
"
|
||||||
|
fn main()
|
||||||
|
let x = 42
|
||||||
|
x = 43
|
||||||
|
end
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut symbol_table = SymbolTable::new();
|
||||||
|
compilation_unit
|
||||||
|
.gather_declared_names(&mut symbol_table)
|
||||||
|
.unwrap();
|
||||||
|
compilation_unit.check_name_usages(&symbol_table).unwrap();
|
||||||
|
match compilation_unit.type_check(&symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
panic!("Type check missed diagnostic.");
|
||||||
|
}
|
||||||
|
Err(diagnostics) => {
|
||||||
|
assert_eq!(diagnostics.len(), 1);
|
||||||
|
assert_eq!(diagnostics[0].error_code().unwrap(), ASSIGN_LHS_IMMUTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,8 +56,11 @@ impl Field {
|
|||||||
field_index: usize,
|
field_index: usize,
|
||||||
) -> Result<(), Vec<Diagnostic>> {
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
// 1. insert field symbol
|
// 1. insert field symbol
|
||||||
let to_insert =
|
let to_insert = FieldSymbol::new(
|
||||||
FieldSymbol::new(&self.declared_name, self.declared_name_source_range.clone());
|
&self.declared_name,
|
||||||
|
self.declared_name_source_range.clone(),
|
||||||
|
self.is_mut,
|
||||||
|
);
|
||||||
|
|
||||||
let field_symbol = symbol_table
|
let field_symbol = symbol_table
|
||||||
.insert_field_symbol(to_insert)
|
.insert_field_symbol(to_insert)
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use std::rc::Rc;
|
|||||||
pub struct LetStatement {
|
pub struct LetStatement {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
initializer: Box<Expression>,
|
initializer: Box<Expression>,
|
||||||
scope_id: Option<usize>,
|
scope_id: Option<usize>,
|
||||||
}
|
}
|
||||||
@ -23,11 +24,13 @@ impl LetStatement {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
declared_name: &str,
|
declared_name: &str,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
initializer: Expression,
|
initializer: Expression,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.into(),
|
declared_name: declared_name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
|
is_mut,
|
||||||
initializer: initializer.into(),
|
initializer: initializer.into(),
|
||||||
scope_id: None,
|
scope_id: None,
|
||||||
}
|
}
|
||||||
@ -61,6 +64,7 @@ impl LetStatement {
|
|||||||
let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
|
let insert_result = symbol_table.insert_variable_symbol(VariableSymbol::new(
|
||||||
&self.declared_name,
|
&self.declared_name,
|
||||||
self.declared_name_source_range.clone(),
|
self.declared_name_source_range.clone(),
|
||||||
|
self.is_mut,
|
||||||
));
|
));
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
if let Err(symbol_insert_error) = insert_result {
|
||||||
match symbol_insert_error {
|
match symbol_insert_error {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
pub mod add_expression;
|
pub mod add_expression;
|
||||||
|
pub mod assign_statement;
|
||||||
pub mod call;
|
pub mod call;
|
||||||
pub mod class;
|
pub mod class;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::expression_statement::ExpressionStatement;
|
use crate::ast::expression_statement::ExpressionStatement;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
@ -8,6 +9,7 @@ use crate::type_info::TypeInfo;
|
|||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
Expression(ExpressionStatement),
|
Expression(ExpressionStatement),
|
||||||
|
Assign(AssignStatement),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
@ -20,6 +22,9 @@ impl Statement {
|
|||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.gather_declared_names(symbol_table)
|
expression_statement.gather_declared_names(symbol_table)
|
||||||
}
|
}
|
||||||
|
Statement::Assign(assign_statement) => {
|
||||||
|
assign_statement.gather_declared_names(symbol_table)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +34,7 @@ impl Statement {
|
|||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.check_name_usages(symbol_table)
|
expression_statement.check_name_usages(symbol_table)
|
||||||
}
|
}
|
||||||
|
Statement::Assign(assign_statement) => assign_statement.check_name_usages(symbol_table),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +48,7 @@ impl Statement {
|
|||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.type_check(symbol_table, must_return_type_info)
|
expression_statement.type_check(symbol_table, must_return_type_info)
|
||||||
}
|
}
|
||||||
|
Statement::Assign(assign_statement) => assign_statement.type_check(symbol_table),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +65,9 @@ impl Statement {
|
|||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.to_ir(builder, symbol_table, should_return_value);
|
expression_statement.to_ir(builder, symbol_table, should_return_value);
|
||||||
}
|
}
|
||||||
|
Statement::Assign(assign_statement) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
dmc-lib/src/error_codes.rs
Normal file
5
dmc-lib/src/error_codes.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub type ErrorCode = usize;
|
||||||
|
|
||||||
|
pub const ASSIGN_MISMATCHED_TYPES: ErrorCode = 16;
|
||||||
|
pub const ASSIGN_NO_L_VALUE: ErrorCode = 17;
|
||||||
|
pub const ASSIGN_LHS_IMMUTABLE: ErrorCode = 18;
|
||||||
@ -1,6 +1,7 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod constants_table;
|
pub mod constants_table;
|
||||||
pub mod diagnostic;
|
pub mod diagnostic;
|
||||||
|
pub mod error_codes;
|
||||||
pub mod ir;
|
pub mod ir;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::ast::add_expression::AddExpression;
|
use crate::ast::add_expression::AddExpression;
|
||||||
|
use crate::ast::assign_statement::AssignStatement;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::class::Class;
|
use crate::ast::class::Class;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
@ -621,24 +622,44 @@ impl<'a> Parser<'a> {
|
|||||||
let current = self.get_current();
|
let current = self.get_current();
|
||||||
match current.kind() {
|
match current.kind() {
|
||||||
TokenKind::Let => Ok(Statement::Let(self.let_statement()?)),
|
TokenKind::Let => Ok(Statement::Let(self.let_statement()?)),
|
||||||
_ => Ok(Statement::Expression(self.expression_statement()?)),
|
_ => self.expression_statement_or_assign_statement(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn let_statement(&mut self) -> Result<LetStatement, Vec<Diagnostic>> {
|
fn let_statement(&mut self) -> Result<LetStatement, Vec<Diagnostic>> {
|
||||||
self.expect_advance(TokenKind::Let)?;
|
self.expect_advance(TokenKind::Let)?;
|
||||||
|
|
||||||
|
let is_mut = if self.current.is_some() && self.peek_current(TokenKind::Mut) {
|
||||||
|
self.advance();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
let identifier = self.expect_advance(TokenKind::Identifier)?;
|
||||||
self.expect_advance(TokenKind::Equals)?;
|
self.expect_advance(TokenKind::Equals)?;
|
||||||
let expression = self.expression()?;
|
let expression = self.expression()?;
|
||||||
Ok(LetStatement::new(
|
Ok(LetStatement::new(
|
||||||
self.token_text(&identifier),
|
self.token_text(&identifier),
|
||||||
SourceRange::new(identifier.start(), identifier.end()),
|
SourceRange::new(identifier.start(), identifier.end()),
|
||||||
|
is_mut,
|
||||||
expression,
|
expression,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_statement(&mut self) -> Result<ExpressionStatement, Vec<Diagnostic>> {
|
fn expression_statement_or_assign_statement(&mut self) -> Result<Statement, Vec<Diagnostic>> {
|
||||||
Ok(ExpressionStatement::new(self.expression()?))
|
let base = self.expression()?;
|
||||||
|
if self.current.is_some() && self.peek_current(TokenKind::Equals) {
|
||||||
|
Ok(Statement::Assign(self.assign_rhs(base)?))
|
||||||
|
} else {
|
||||||
|
Ok(Statement::Expression(ExpressionStatement::new(base)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assign_rhs(&mut self, destination: Expression) -> Result<AssignStatement, Vec<Diagnostic>> {
|
||||||
|
self.expect_advance(TokenKind::Equals)?;
|
||||||
|
let value = self.expression()?;
|
||||||
|
Ok(AssignStatement::new(destination, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
@ -919,6 +940,18 @@ mod smoke_tests {
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_assign() {
|
||||||
|
smoke_test(
|
||||||
|
"
|
||||||
|
fn main()
|
||||||
|
let mut x = 4
|
||||||
|
x = 42
|
||||||
|
end
|
||||||
|
",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_read_field::IrReadField;
|
use crate::ir::ir_read_field::IrReadField;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
use crate::ir::ir_variable::IrVariable;
|
||||||
|
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::field_symbol::FieldSymbol;
|
||||||
@ -41,6 +42,37 @@ impl ExpressibleSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_mut(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ExpressibleSymbol::Field(field_symbol) => field_symbol.borrow().is_mut(),
|
||||||
|
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol.borrow().is_mut(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_range(&self) -> SourceRange {
|
||||||
|
match self {
|
||||||
|
ExpressibleSymbol::Class(class_symbol) => {
|
||||||
|
class_symbol.borrow().declared_name_source_range().clone()
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Field(field_symbol) => {
|
||||||
|
field_symbol.borrow().declared_name_source_range().clone()
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Function(function_symbol) => function_symbol
|
||||||
|
.borrow()
|
||||||
|
.declared_name_source_range()
|
||||||
|
.clone(),
|
||||||
|
ExpressibleSymbol::Parameter(parameter_symbol) => parameter_symbol
|
||||||
|
.borrow()
|
||||||
|
.declared_name_source_range()
|
||||||
|
.clone(),
|
||||||
|
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol
|
||||||
|
.borrow()
|
||||||
|
.declared_name_source_range()
|
||||||
|
.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ir_expression(&self, builder: &mut IrBuilder) -> IrExpression {
|
pub fn ir_expression(&self, builder: &mut IrBuilder) -> IrExpression {
|
||||||
match self {
|
match self {
|
||||||
ExpressibleSymbol::Class(class_symbol) => {
|
ExpressibleSymbol::Class(class_symbol) => {
|
||||||
|
|||||||
@ -6,20 +6,30 @@ use std::rc::Rc;
|
|||||||
pub struct FieldSymbol {
|
pub struct FieldSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
type_info: Option<TypeInfo>,
|
type_info: Option<TypeInfo>,
|
||||||
field_index: Option<usize>,
|
field_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldSymbol {
|
impl FieldSymbol {
|
||||||
pub fn new(declared_name: &Rc<str>, declared_name_source_range: SourceRange) -> Self {
|
pub fn new(
|
||||||
|
declared_name: &Rc<str>,
|
||||||
|
declared_name_source_range: SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.clone(),
|
declared_name: declared_name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
|
is_mut,
|
||||||
type_info: None,
|
type_info: None,
|
||||||
field_index: None,
|
field_index: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_mut(&self) -> bool {
|
||||||
|
self.is_mut
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
||||||
self.type_info = Some(type_info);
|
self.type_info = Some(type_info);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,20 +8,26 @@ use std::rc::Rc;
|
|||||||
pub struct VariableSymbol {
|
pub struct VariableSymbol {
|
||||||
declared_name: Rc<str>,
|
declared_name: Rc<str>,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
is_mut: bool,
|
||||||
type_info: Option<TypeInfo>,
|
type_info: Option<TypeInfo>,
|
||||||
vr_variable: Option<Rc<RefCell<IrVariable>>>,
|
vr_variable: Option<Rc<RefCell<IrVariable>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableSymbol {
|
impl VariableSymbol {
|
||||||
pub fn new(name: &Rc<str>, declared_name_source_range: SourceRange) -> Self {
|
pub fn new(name: &Rc<str>, declared_name_source_range: SourceRange, is_mut: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: name.clone(),
|
declared_name: name.clone(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
|
is_mut,
|
||||||
type_info: None,
|
type_info: None,
|
||||||
vr_variable: None,
|
vr_variable: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_mut(&self) -> bool {
|
||||||
|
self.is_mut
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
pub fn set_type_info(&mut self, type_info: TypeInfo) {
|
||||||
self.type_info = Some(type_info);
|
self.type_info = Some(type_info);
|
||||||
}
|
}
|
||||||
|
|||||||
7
examples/simple_assign.dm
Normal file
7
examples/simple_assign.dm
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
let mut x = 4
|
||||||
|
x = 7
|
||||||
|
println(x)
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user