Continue fixing the compiler to work with the new instructions
This commit is contained in:
parent
a57268fcba
commit
ef22fa18b6
@ -61,10 +61,7 @@ pub struct Compiler<'src> {
|
|||||||
previous_position: Span,
|
previous_position: Span,
|
||||||
|
|
||||||
return_type: Option<Type>,
|
return_type: Option<Type>,
|
||||||
optimization_count: usize,
|
|
||||||
previous_expression_type: Type,
|
|
||||||
minimum_register: u16,
|
minimum_register: u16,
|
||||||
|
|
||||||
block_index: u8,
|
block_index: u8,
|
||||||
current_scope: Scope,
|
current_scope: Scope,
|
||||||
}
|
}
|
||||||
@ -88,8 +85,6 @@ impl<'src> Compiler<'src> {
|
|||||||
previous_token: Token::Eof,
|
previous_token: Token::Eof,
|
||||||
previous_position: Span(0, 0),
|
previous_position: Span(0, 0),
|
||||||
return_type: None,
|
return_type: None,
|
||||||
optimization_count: 0,
|
|
||||||
previous_expression_type: Type::None,
|
|
||||||
minimum_register: 0,
|
minimum_register: 0,
|
||||||
block_index: 0,
|
block_index: 0,
|
||||||
current_scope: Scope::default(),
|
current_scope: Scope::default(),
|
||||||
@ -97,7 +92,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(mut self) -> Chunk {
|
pub fn finish(mut self) -> Chunk {
|
||||||
log::info!("End chunk with {} optimizations", self.optimization_count);
|
log::info!("End chunk");
|
||||||
|
|
||||||
if let Type::None = *self.chunk.r#type().return_type {
|
if let Type::None = *self.chunk.r#type().return_type {
|
||||||
self.chunk.set_type(FunctionType {
|
self.chunk.set_type(FunctionType {
|
||||||
@ -120,14 +115,14 @@ impl<'src> Compiler<'src> {
|
|||||||
self.chunk
|
self.chunk
|
||||||
.instructions()
|
.instructions()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(instruction, _, _)| {
|
.rev()
|
||||||
|
.find_map(|(instruction, _, _)| {
|
||||||
if instruction.yields_value() {
|
if instruction.yields_value() {
|
||||||
Some(instruction.a() + 1)
|
Some(instruction.a() + 1)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.max()
|
|
||||||
.unwrap_or(self.minimum_register)
|
.unwrap_or(self.minimum_register)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,107 +271,12 @@ impl<'src> Compiler<'src> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_instruction_type(&self, instruction: &Instruction) -> Result<Type, CompileError> {
|
fn get_last_instruction_type(&self) -> Type {
|
||||||
match instruction.operation() {
|
self.chunk
|
||||||
Operation::LoadBoolean => Ok(Type::Boolean),
|
.instructions()
|
||||||
Operation::LoadConstant => {
|
.last()
|
||||||
let LoadConstant { constant_index, .. } = LoadConstant::from(instruction);
|
.map(|(_, r#type, _)| r#type.clone())
|
||||||
|
.unwrap_or(Type::None)
|
||||||
self.chunk
|
|
||||||
.get_constant(constant_index)
|
|
||||||
.map(|value| value.r#type())
|
|
||||||
.map_err(|error| CompileError::Chunk {
|
|
||||||
error,
|
|
||||||
position: self.current_position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Operation::LoadList => {
|
|
||||||
let LoadList { start_register, .. } = LoadList::from(instruction);
|
|
||||||
let first_instruction = self
|
|
||||||
.chunk
|
|
||||||
.get_instruction(start_register as usize)
|
|
||||||
.map_err(|error| CompileError::Chunk {
|
|
||||||
error,
|
|
||||||
position: self.current_position,
|
|
||||||
})?
|
|
||||||
.0; // TODO: Handle the case that the first instruction is Close
|
|
||||||
let item_type = self.get_instruction_type(&first_instruction)?;
|
|
||||||
|
|
||||||
Ok(Type::List(Box::new(item_type)))
|
|
||||||
}
|
|
||||||
Operation::LoadSelf => Ok(Type::SelfChunk),
|
|
||||||
Operation::GetLocal => {
|
|
||||||
let GetLocal { local_index, .. } = GetLocal::from(instruction);
|
|
||||||
|
|
||||||
self.get_local(local_index)
|
|
||||||
.map(|local| local.r#type.clone())
|
|
||||||
}
|
|
||||||
Operation::Add => {
|
|
||||||
let Add { left, .. } = Add::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&left)
|
|
||||||
}
|
|
||||||
Operation::Subtract => {
|
|
||||||
let Subtract { left, .. } = Subtract::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&left)
|
|
||||||
}
|
|
||||||
Operation::Multiply => {
|
|
||||||
let Multiply { left, .. } = Multiply::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&left)
|
|
||||||
}
|
|
||||||
Operation::Divide => {
|
|
||||||
let Divide { left, .. } = Divide::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&left)
|
|
||||||
}
|
|
||||||
Operation::Modulo => {
|
|
||||||
let Modulo { left, .. } = Modulo::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&left)
|
|
||||||
}
|
|
||||||
Operation::Negate => {
|
|
||||||
let Negate { argument, .. } = Negate::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&argument)
|
|
||||||
}
|
|
||||||
Operation::Not => {
|
|
||||||
let Not { argument, .. } = Not::from(instruction);
|
|
||||||
|
|
||||||
self.get_argument_type(&argument)
|
|
||||||
}
|
|
||||||
Operation::Call => {
|
|
||||||
let Call { function, .. } = Call::from(instruction);
|
|
||||||
let function_type = self.get_argument_type(&function)?;
|
|
||||||
|
|
||||||
if let Type::Function(FunctionType { return_type, .. }) = function_type {
|
|
||||||
Ok(*return_type)
|
|
||||||
} else {
|
|
||||||
Err(CompileError::ExpectedFunctionType {
|
|
||||||
found: function_type,
|
|
||||||
position: self.current_position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Operation::CallNative => {
|
|
||||||
let CallNative { function, .. } = CallNative::from(instruction);
|
|
||||||
|
|
||||||
Ok(*function.r#type().return_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
Operation::Move
|
|
||||||
| Operation::Close
|
|
||||||
| Operation::DefineLocal
|
|
||||||
| Operation::SetLocal
|
|
||||||
| Operation::Test
|
|
||||||
| Operation::TestSet
|
|
||||||
| Operation::Equal
|
|
||||||
| Operation::Less
|
|
||||||
| Operation::LessEqual
|
|
||||||
| Operation::Jump
|
|
||||||
| Operation::Return => Ok(Type::None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_argument_type(&self, argument: &Argument) -> Result<Type, CompileError> {
|
pub fn get_argument_type(&self, argument: &Argument) -> Result<Type, CompileError> {
|
||||||
@ -445,15 +345,12 @@ impl<'src> Compiler<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
fn emit_instruction(&mut self, instruction: Instruction, r#type: Type, position: Span) {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Emitting {} at {}",
|
"Emitting {} at {}",
|
||||||
instruction.operation().to_string().bold(),
|
instruction.operation().to_string().bold(),
|
||||||
position.to_string()
|
position.to_string()
|
||||||
);
|
);
|
||||||
let r#type = self
|
|
||||||
.get_instruction_type(&instruction)
|
|
||||||
.unwrap_or(Type::None);
|
|
||||||
|
|
||||||
self.chunk
|
self.chunk
|
||||||
.instructions_mut()
|
.instructions_mut()
|
||||||
@ -465,6 +362,7 @@ impl<'src> Compiler<'src> {
|
|||||||
constant: ConcreteValue,
|
constant: ConcreteValue,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
|
let r#type = constant.r#type();
|
||||||
let constant_index = self.chunk.push_or_get_constant(constant);
|
let constant_index = self.chunk.push_or_get_constant(constant);
|
||||||
let destination = self.next_register();
|
let destination = self.next_register();
|
||||||
let instruction = Instruction::from(LoadConstant {
|
let instruction = Instruction::from(LoadConstant {
|
||||||
@ -473,7 +371,7 @@ impl<'src> Compiler<'src> {
|
|||||||
jump_next: false,
|
jump_next: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(instruction, position);
|
self.emit_instruction(instruction, r#type, position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -492,9 +390,7 @@ impl<'src> Compiler<'src> {
|
|||||||
jump_next: false,
|
jump_next: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(instruction, position);
|
self.emit_instruction(instruction, Type::Boolean, position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::Boolean;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -518,8 +414,6 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::Byte;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::ExpectedToken {
|
Err(CompileError::ExpectedToken {
|
||||||
@ -540,8 +434,6 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::Character;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::ExpectedToken {
|
Err(CompileError::ExpectedToken {
|
||||||
@ -568,8 +460,6 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::Float;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::ExpectedToken {
|
Err(CompileError::ExpectedToken {
|
||||||
@ -596,8 +486,6 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::Integer;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::ExpectedToken {
|
Err(CompileError::ExpectedToken {
|
||||||
@ -618,8 +506,6 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::String;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(CompileError::ExpectedToken {
|
Err(CompileError::ExpectedToken {
|
||||||
@ -645,7 +531,8 @@ impl<'src> Compiler<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let (previous_instruction, _, previous_position) = self.pop_last_instruction()?;
|
let (previous_instruction, previous_type, previous_position) =
|
||||||
|
self.pop_last_instruction()?;
|
||||||
let argument = if let Some(argument) = previous_instruction.destination_as_argument() {
|
let argument = if let Some(argument) = previous_instruction.destination_as_argument() {
|
||||||
argument
|
argument
|
||||||
} else {
|
} else {
|
||||||
@ -674,11 +561,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.emit_instruction(instruction, operator_position);
|
self.emit_instruction(instruction, previous_type, operator_position);
|
||||||
|
|
||||||
if let TokenKind::Bang = operator.kind() {
|
|
||||||
self.previous_expression_type = Type::Boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -693,22 +576,14 @@ impl<'src> Compiler<'src> {
|
|||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
let push_back = matches!(
|
let push_back = !matches!(
|
||||||
instruction.operation(),
|
instruction.operation(),
|
||||||
Operation::Add
|
Operation::LoadConstant | Operation::GetLocal,
|
||||||
| Operation::Subtract
|
|
||||||
| Operation::Multiply
|
|
||||||
| Operation::Divide
|
|
||||||
| Operation::Modulo
|
|
||||||
| Operation::Equal
|
|
||||||
| Operation::Less
|
|
||||||
| Operation::LessEqual
|
|
||||||
| Operation::Test
|
|
||||||
| Operation::TestSet
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok((argument, push_back))
|
Ok((argument, push_back))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_math_binary(&mut self) -> Result<(), CompileError> {
|
fn parse_math_binary(&mut self) -> Result<(), CompileError> {
|
||||||
let (left_instruction, left_type, left_position) =
|
let (left_instruction, left_type, left_position) =
|
||||||
self.chunk.instructions_mut().pop().ok_or_else(|| {
|
self.chunk.instructions_mut().pop().ok_or_else(|| {
|
||||||
@ -726,43 +601,52 @@ impl<'src> Compiler<'src> {
|
|||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
let rule = ParseRule::from(&operator);
|
let rule = ParseRule::from(&operator);
|
||||||
let is_assignment =
|
let is_assignment = matches!(
|
||||||
if let Token::PlusEqual | Token::MinusEqual | Token::StarEqual | Token::SlashEqual =
|
operator,
|
||||||
operator
|
Token::PlusEqual | Token::MinusEqual | Token::StarEqual | Token::SlashEqual
|
||||||
{
|
);
|
||||||
if !left_is_mutable_local {
|
let r#type = if is_assignment {
|
||||||
return Err(CompileError::ExpectedMutableVariable {
|
Type::None
|
||||||
found: self.previous_token.to_owned(),
|
} else {
|
||||||
position: left_position,
|
left_type.clone()
|
||||||
});
|
};
|
||||||
}
|
|
||||||
|
|
||||||
true
|
if is_assignment && !left_is_mutable_local {
|
||||||
} else {
|
return Err(CompileError::ExpectedMutableVariable {
|
||||||
false
|
found: self.previous_token.to_owned(),
|
||||||
};
|
position: left_position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if push_back_left {
|
||||||
|
self.chunk
|
||||||
|
.instructions_mut()
|
||||||
|
.push((left_instruction, left_type, left_position));
|
||||||
|
}
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
let (right_instruction, right_type, right_position) = self.pop_last_instruction()?;
|
let (right_instruction, right_type, right_position) = self.pop_last_instruction()?;
|
||||||
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
||||||
|
|
||||||
|
if push_back_right {
|
||||||
|
self.chunk
|
||||||
|
.instructions_mut()
|
||||||
|
.push((right_instruction, right_type, right_position));
|
||||||
|
}
|
||||||
|
|
||||||
let destination = if is_assignment {
|
let destination = if is_assignment {
|
||||||
left.index()
|
left.index()
|
||||||
} else {
|
} else {
|
||||||
self.next_register()
|
self.next_register()
|
||||||
};
|
};
|
||||||
let instruction = match operator {
|
let instruction = match operator {
|
||||||
Token::Plus => Instruction::add(destination, left, right),
|
Token::Plus | Token::PlusEqual => Instruction::add(destination, left, right),
|
||||||
Token::PlusEqual => Instruction::add(destination, left, right),
|
Token::Minus | Token::MinusEqual => Instruction::subtract(destination, left, right),
|
||||||
Token::Minus => Instruction::subtract(destination, left, right),
|
Token::Star | Token::StarEqual => Instruction::multiply(destination, left, right),
|
||||||
Token::MinusEqual => Instruction::subtract(destination, left, right),
|
Token::Slash | Token::SlashEqual => Instruction::divide(destination, left, right),
|
||||||
Token::Star => Instruction::multiply(destination, left, right),
|
Token::Percent | Token::PercentEqual => Instruction::modulo(destination, left, right),
|
||||||
Token::StarEqual => Instruction::multiply(destination, left, right),
|
|
||||||
Token::Slash => Instruction::divide(destination, left, right),
|
|
||||||
Token::SlashEqual => Instruction::divide(destination, left, right),
|
|
||||||
Token::Percent => Instruction::modulo(destination, left, right),
|
|
||||||
Token::PercentEqual => Instruction::modulo(destination, left, right),
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CompileError::ExpectedTokenMultiple {
|
return Err(CompileError::ExpectedTokenMultiple {
|
||||||
expected: &[
|
expected: &[
|
||||||
@ -783,25 +667,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if push_back_left {
|
self.emit_instruction(instruction, r#type, operator_position);
|
||||||
self.chunk
|
|
||||||
.instructions_mut()
|
|
||||||
.push((left_instruction, left_type, left_position));
|
|
||||||
}
|
|
||||||
|
|
||||||
if push_back_right {
|
|
||||||
self.chunk
|
|
||||||
.instructions_mut()
|
|
||||||
.push((right_instruction, right_type, right_position));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.emit_instruction(instruction, operator_position);
|
|
||||||
|
|
||||||
if is_assignment {
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
} else {
|
|
||||||
self.previous_expression_type = self.get_instruction_type(&left_instruction)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -848,7 +714,7 @@ impl<'src> Compiler<'src> {
|
|||||||
position: right_position,
|
position: right_position,
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
let instruction = match operator {
|
let comparison = match operator {
|
||||||
Token::DoubleEqual => Instruction::from(Equal {
|
Token::DoubleEqual => Instruction::from(Equal {
|
||||||
value: true,
|
value: true,
|
||||||
left,
|
left,
|
||||||
@ -911,12 +777,10 @@ impl<'src> Compiler<'src> {
|
|||||||
jump_next: false,
|
jump_next: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(instruction, operator_position);
|
self.emit_instruction(comparison, Type::None, operator_position);
|
||||||
self.emit_instruction(jump, operator_position);
|
self.emit_instruction(jump, Type::None, operator_position);
|
||||||
self.emit_instruction(load_true, operator_position);
|
self.emit_instruction(load_true, Type::Boolean, operator_position);
|
||||||
self.emit_instruction(load_false, operator_position);
|
self.emit_instruction(load_false, Type::Boolean, operator_position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::Boolean;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -961,13 +825,11 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.emit_instruction(left_instruction, left_position);
|
self.emit_instruction(left_instruction, left_type, left_position);
|
||||||
self.emit_instruction(test, operator_position);
|
self.emit_instruction(test, Type::None, operator_position);
|
||||||
self.emit_instruction(jump, operator_position);
|
self.emit_instruction(jump, Type::None, operator_position);
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
self.previous_expression_type = Type::Boolean;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,9 +854,7 @@ impl<'src> Compiler<'src> {
|
|||||||
let destination = self.next_register();
|
let destination = self.next_register();
|
||||||
let load_self = Instruction::from(LoadSelf { destination });
|
let load_self = Instruction::from(LoadSelf { destination });
|
||||||
|
|
||||||
self.emit_instruction(load_self, start_position);
|
self.emit_instruction(load_self, Type::SelfChunk, start_position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::SelfChunk;
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
@ -1032,16 +892,11 @@ impl<'src> Compiler<'src> {
|
|||||||
local_index,
|
local_index,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(set_local, start_position);
|
self.emit_instruction(set_local, Type::None, start_position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
|
|
||||||
let mut optimizer = Optimizer::new(&mut self.chunk);
|
let mut optimizer = Optimizer::new(&mut self.chunk);
|
||||||
let optimized = optimizer.optimize_set_local();
|
|
||||||
|
|
||||||
if optimized {
|
optimizer.optimize_set_local();
|
||||||
self.optimization_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -1053,9 +908,7 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
let r#type = self.get_local(local_index)?.r#type.clone();
|
let r#type = self.get_local(local_index)?.r#type.clone();
|
||||||
|
|
||||||
self.emit_instruction(get_local, self.previous_position);
|
self.emit_instruction(get_local, r#type, self.previous_position);
|
||||||
|
|
||||||
self.previous_expression_type = r#type;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1109,25 +962,19 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
if expected_register > start_register {
|
|
||||||
if let Err(conflict) = item_type.check(&self.previous_expression_type) {
|
|
||||||
return Err(CompileError::ListItemTypeConflict {
|
|
||||||
conflict,
|
|
||||||
position: self.previous_position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item_type = self.previous_expression_type.clone();
|
|
||||||
let actual_register = self.next_register() - 1;
|
let actual_register = self.next_register() - 1;
|
||||||
|
|
||||||
|
if item_type == Type::Any {
|
||||||
|
item_type = self.get_last_instruction_type();
|
||||||
|
}
|
||||||
|
|
||||||
if expected_register < actual_register {
|
if expected_register < actual_register {
|
||||||
let close = Instruction::from(Close {
|
let close = Instruction::from(Close {
|
||||||
from: expected_register,
|
from: expected_register,
|
||||||
to: actual_register,
|
to: actual_register,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(close, self.current_position);
|
self.emit_instruction(close, Type::None, self.current_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allow(Token::Comma)?;
|
self.allow(Token::Comma)?;
|
||||||
@ -1140,9 +987,7 @@ impl<'src> Compiler<'src> {
|
|||||||
start_register,
|
start_register,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(load_list, Span(start, end));
|
self.emit_instruction(load_list, Type::List(Box::new(item_type)), Span(start, end));
|
||||||
|
|
||||||
self.previous_expression_type = Type::List(Box::new(item_type));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1170,7 +1015,7 @@ impl<'src> Compiler<'src> {
|
|||||||
value: true,
|
value: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(test, self.current_position)
|
self.emit_instruction(test, Type::None, self.current_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
let if_block_start = self.chunk.len();
|
let if_block_start = self.chunk.len();
|
||||||
@ -1188,7 +1033,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let if_block_end = self.chunk.len();
|
let if_block_end = self.chunk.len();
|
||||||
let mut if_block_distance = (if_block_end - if_block_start) as u16;
|
let mut if_block_distance = (if_block_end - if_block_start) as u16;
|
||||||
let if_block_type = self.previous_expression_type.clone();
|
let if_block_type = self.get_last_instruction_type();
|
||||||
let if_last_register = self.next_register().saturating_sub(1);
|
let if_last_register = self.next_register().saturating_sub(1);
|
||||||
|
|
||||||
if let Token::Else = self.current_token {
|
if let Token::Else = self.current_token {
|
||||||
@ -1205,7 +1050,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
} else if self.previous_expression_type != Type::None {
|
} else if if_block_type != Type::None {
|
||||||
return Err(CompileError::IfMissingElse {
|
return Err(CompileError::IfMissingElse {
|
||||||
position: Span(if_block_start_position.0, self.current_position.1),
|
position: Span(if_block_start_position.0, self.current_position.1),
|
||||||
});
|
});
|
||||||
@ -1215,8 +1060,9 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
let else_block_end = self.chunk.len();
|
let else_block_end = self.chunk.len();
|
||||||
let else_block_distance = (else_block_end - if_block_end) as u16;
|
let else_block_distance = (else_block_end - if_block_end) as u16;
|
||||||
|
let else_block_type = self.get_last_instruction_type();
|
||||||
|
|
||||||
if let Err(conflict) = if_block_type.check(&self.previous_expression_type) {
|
if let Err(conflict) = if_block_type.check(&else_block_type) {
|
||||||
return Err(CompileError::IfElseBranchMismatch {
|
return Err(CompileError::IfElseBranchMismatch {
|
||||||
conflict,
|
conflict,
|
||||||
position: Span(if_block_start_position.0, self.current_position.1),
|
position: Span(if_block_start_position.0, self.current_position.1),
|
||||||
@ -1267,9 +1113,7 @@ impl<'src> Compiler<'src> {
|
|||||||
if self.chunk.len() >= 4 {
|
if self.chunk.len() >= 4 {
|
||||||
let mut optimizer = Optimizer::new(&mut self.chunk);
|
let mut optimizer = Optimizer::new(&mut self.chunk);
|
||||||
|
|
||||||
if optimizer.optimize_control_flow() {
|
optimizer.optimize_control_flow();
|
||||||
self.optimization_count += 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let else_last_register = self.next_register().saturating_sub(1);
|
let else_last_register = self.next_register().saturating_sub(1);
|
||||||
@ -1279,7 +1123,7 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if if_last_register < else_last_register {
|
if if_last_register < else_last_register {
|
||||||
self.emit_instruction(r#move, self.current_position);
|
self.emit_instruction(r#move, Type::None, self.current_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1327,9 +1171,7 @@ impl<'src> Compiler<'src> {
|
|||||||
is_positive: false,
|
is_positive: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(jump_back, self.current_position);
|
self.emit_instruction(jump_back, Type::None, self.current_position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1353,23 +1195,23 @@ impl<'src> Compiler<'src> {
|
|||||||
to: actual_register,
|
to: actual_register,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(close, self.current_position);
|
self.emit_instruction(close, Type::None, self.current_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allow(Token::Comma)?;
|
self.allow(Token::Comma)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.previous_expression_type = *function.r#type().return_type;
|
|
||||||
let end = self.previous_position.1;
|
let end = self.previous_position.1;
|
||||||
let destination = self.next_register();
|
let destination = self.next_register();
|
||||||
let argument_count = destination - start_register;
|
let argument_count = destination - start_register;
|
||||||
|
let return_type = *function.r#type().return_type;
|
||||||
let call_native = Instruction::from(CallNative {
|
let call_native = Instruction::from(CallNative {
|
||||||
destination,
|
destination,
|
||||||
function,
|
function,
|
||||||
argument_count,
|
argument_count,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(call_native, Span(start, end));
|
self.emit_instruction(call_native, return_type, Span(start, end));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1391,7 +1233,9 @@ impl<'src> Compiler<'src> {
|
|||||||
fn parse_expression(&mut self) -> Result<(), CompileError> {
|
fn parse_expression(&mut self) -> Result<(), CompileError> {
|
||||||
self.parse(Precedence::None)?;
|
self.parse(Precedence::None)?;
|
||||||
|
|
||||||
if self.previous_expression_type == Type::None || self.chunk.is_empty() {
|
let expression_type = self.get_last_instruction_type();
|
||||||
|
|
||||||
|
if expression_type == Type::None || self.chunk.is_empty() {
|
||||||
return Err(CompileError::ExpectedExpression {
|
return Err(CompileError::ExpectedExpression {
|
||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
@ -1417,7 +1261,10 @@ impl<'src> Compiler<'src> {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
self.update_return_type(self.previous_expression_type.clone())?;
|
|
||||||
|
let expression_type = self.get_last_instruction_type();
|
||||||
|
|
||||||
|
self.update_return_type(expression_type)?;
|
||||||
|
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
@ -1426,9 +1273,7 @@ impl<'src> Compiler<'src> {
|
|||||||
should_return_value,
|
should_return_value,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(r#return, Span(start, end));
|
self.emit_instruction(r#return, Type::None, Span(start, end));
|
||||||
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1439,14 +1284,15 @@ impl<'src> Compiler<'src> {
|
|||||||
should_return_value: false,
|
should_return_value: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(r#return, self.current_position);
|
self.emit_instruction(r#return, Type::None, self.current_position);
|
||||||
} else {
|
} else {
|
||||||
let should_return_value = self.previous_expression_type != Type::None;
|
let previous_expression_type = self.get_last_instruction_type();
|
||||||
|
let should_return_value = previous_expression_type != Type::None;
|
||||||
let r#return = Instruction::from(Return {
|
let r#return = Instruction::from(Return {
|
||||||
should_return_value,
|
should_return_value,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(r#return, self.current_position);
|
self.emit_instruction(r#return, Type::None, self.current_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1495,9 +1341,7 @@ impl<'src> Compiler<'src> {
|
|||||||
is_mutable,
|
is_mutable,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(define_local, position);
|
self.emit_instruction(define_local, Type::None, position);
|
||||||
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1601,7 +1445,7 @@ impl<'src> Compiler<'src> {
|
|||||||
if let Some((identifier, position)) = identifier_info {
|
if let Some((identifier, position)) = identifier_info {
|
||||||
let (local_index, _) = self.declare_local(
|
let (local_index, _) = self.declare_local(
|
||||||
identifier,
|
identifier,
|
||||||
Type::Function(function_type),
|
Type::Function(function_type.clone()),
|
||||||
false,
|
false,
|
||||||
self.current_scope,
|
self.current_scope,
|
||||||
);
|
);
|
||||||
@ -1616,10 +1460,12 @@ impl<'src> Compiler<'src> {
|
|||||||
is_mutable: false,
|
is_mutable: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(load_constant, Span(function_start, function_end));
|
self.emit_instruction(
|
||||||
self.emit_instruction(define_local, position);
|
load_constant,
|
||||||
|
Type::Function(function_type),
|
||||||
self.previous_expression_type = Type::None;
|
Span(function_start, function_end),
|
||||||
|
);
|
||||||
|
self.emit_instruction(define_local, Type::None, position);
|
||||||
} else {
|
} else {
|
||||||
let load_constant = Instruction::from(LoadConstant {
|
let load_constant = Instruction::from(LoadConstant {
|
||||||
destination,
|
destination,
|
||||||
@ -1627,9 +1473,11 @@ impl<'src> Compiler<'src> {
|
|||||||
jump_next: false,
|
jump_next: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(load_constant, Span(function_start, function_end));
|
self.emit_instruction(
|
||||||
|
load_constant,
|
||||||
self.previous_expression_type = Type::Function(function_type);
|
Type::Function(function_type),
|
||||||
|
Span(function_start, function_end),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1687,7 +1535,7 @@ impl<'src> Compiler<'src> {
|
|||||||
to: actual_register,
|
to: actual_register,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(close, self.current_position);
|
self.emit_instruction(close, Type::None, self.current_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allow(Token::Comma)?;
|
self.allow(Token::Comma)?;
|
||||||
@ -1702,17 +1550,7 @@ impl<'src> Compiler<'src> {
|
|||||||
argument_count,
|
argument_count,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(call, Span(start, end));
|
self.emit_instruction(call, function_return_type, Span(start, end));
|
||||||
|
|
||||||
self.previous_expression_type = function_return_type;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_semicolon(&mut self) -> Result<(), CompileError> {
|
|
||||||
self.advance()?;
|
|
||||||
|
|
||||||
self.previous_expression_type = Type::None;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -2037,7 +1875,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
|
|||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
Token::Semicolon => ParseRule {
|
Token::Semicolon => ParseRule {
|
||||||
prefix: Some(Compiler::parse_semicolon),
|
prefix: Some(Compiler::expect_expression),
|
||||||
infix: None,
|
infix: None,
|
||||||
precedence: Precedence::None,
|
precedence: Precedence::None,
|
||||||
},
|
},
|
||||||
|
@ -9,14 +9,14 @@ impl From<&Instruction> for Close {
|
|||||||
fn from(instruction: &Instruction) -> Self {
|
fn from(instruction: &Instruction) -> Self {
|
||||||
Close {
|
Close {
|
||||||
from: instruction.b(),
|
from: instruction.b(),
|
||||||
to: instruction.a(),
|
to: instruction.c(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Close> for Instruction {
|
impl From<Close> for Instruction {
|
||||||
fn from(r#move: Close) -> Self {
|
fn from(r#move: Close) -> Self {
|
||||||
*Instruction::new(Operation::Move)
|
*Instruction::new(Operation::Close)
|
||||||
.set_b(r#move.from)
|
.set_b(r#move.from)
|
||||||
.set_c(r#move.to)
|
.set_c(r#move.to)
|
||||||
}
|
}
|
||||||
|
@ -496,7 +496,7 @@ impl Instruction {
|
|||||||
Operation::Close => {
|
Operation::Close => {
|
||||||
let Close { from, to } = Close::from(self);
|
let Close { from, to } = Close::from(self);
|
||||||
|
|
||||||
format!("R{from}..=R{to}")
|
format!("R{from}..R{to}")
|
||||||
}
|
}
|
||||||
Operation::LoadBoolean => {
|
Operation::LoadBoolean => {
|
||||||
let LoadBoolean {
|
let LoadBoolean {
|
||||||
@ -529,7 +529,7 @@ impl Instruction {
|
|||||||
destination,
|
destination,
|
||||||
start_register,
|
start_register,
|
||||||
} = LoadList::from(self);
|
} = LoadList::from(self);
|
||||||
let end_register = destination - 1;
|
let end_register = destination.saturating_sub(1);
|
||||||
|
|
||||||
format!("R{destination} = [R{start_register}..=R{end_register}]",)
|
format!("R{destination} = [R{start_register}..=R{end_register}]",)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user