Add function declarations to the parser
This commit is contained in:
parent
9d5c9d9fd0
commit
13b4cfffcc
@ -135,7 +135,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_instruction(&mut self, instruction: Instruction, position: Span) {
|
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Emitting {} at {}",
|
"Emitting {} at {}",
|
||||||
instruction.operation().to_string().bold(),
|
instruction.operation().to_string().bold(),
|
||||||
@ -183,7 +183,7 @@ impl<'src> Parser<'src> {
|
|||||||
let constant_index = self.chunk.push_constant(value, position)?;
|
let constant_index = self.chunk.push_constant(value, position)?;
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_constant(register, constant_index, false),
|
Instruction::load_constant(register, constant_index, false),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
@ -212,7 +212,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.next_register()
|
self.next_register()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_boolean(register, boolean, false),
|
Instruction::load_boolean(register, boolean, false),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
@ -380,7 +380,7 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if push_back {
|
if push_back {
|
||||||
self.push_instruction(previous_instruction, previous_position);
|
self.emit_instruction(previous_instruction, previous_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
@ -400,7 +400,7 @@ impl<'src> Parser<'src> {
|
|||||||
instruction.set_b_is_constant();
|
instruction.set_b_is_constant();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_instruction(instruction, operator_position);
|
self.emit_instruction(instruction, operator_position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -454,7 +454,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.handle_binary_argument(&left_instruction)?;
|
self.handle_binary_argument(&left_instruction)?;
|
||||||
|
|
||||||
if push_back_left {
|
if push_back_left {
|
||||||
self.push_instruction(left_instruction, left_position);
|
self.emit_instruction(left_instruction, left_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
@ -486,7 +486,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.handle_binary_argument(&right_instruction)?;
|
self.handle_binary_argument(&right_instruction)?;
|
||||||
|
|
||||||
if push_back_right {
|
if push_back_right {
|
||||||
self.push_instruction(right_instruction, right_position);
|
self.emit_instruction(right_instruction, right_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
let register = if left_is_mutable_local {
|
let register = if left_is_mutable_local {
|
||||||
@ -534,7 +534,7 @@ impl<'src> Parser<'src> {
|
|||||||
new_instruction.set_c_is_constant();
|
new_instruction.set_c_is_constant();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_instruction(new_instruction, operator_position);
|
self.emit_instruction(new_instruction, operator_position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -609,22 +609,22 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if push_back_left {
|
if push_back_left {
|
||||||
self.push_instruction(left_instruction, left_position);
|
self.emit_instruction(left_instruction, left_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if push_back_right {
|
if push_back_right {
|
||||||
self.push_instruction(right_instruction, right_position);
|
self.emit_instruction(right_instruction, right_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
|
||||||
self.push_instruction(instruction, operator_position);
|
self.emit_instruction(instruction, operator_position);
|
||||||
self.push_instruction(Instruction::jump(1, true), operator_position);
|
self.emit_instruction(Instruction::jump(1, true), operator_position);
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_boolean(register, true, true),
|
Instruction::load_boolean(register, true, true),
|
||||||
operator_position,
|
operator_position,
|
||||||
);
|
);
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_boolean(register, false, false),
|
Instruction::load_boolean(register, false, false),
|
||||||
operator_position,
|
operator_position,
|
||||||
);
|
);
|
||||||
@ -658,9 +658,9 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
self.push_instruction(left_instruction, left_position);
|
self.emit_instruction(left_instruction, left_position);
|
||||||
self.push_instruction(instruction, operator_position);
|
self.emit_instruction(instruction, operator_position);
|
||||||
self.push_instruction(Instruction::jump(1, true), operator_position);
|
self.emit_instruction(Instruction::jump(1, true), operator_position);
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
self.parse_sub_expression(&rule.precedence)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -712,22 +712,22 @@ impl<'src> Parser<'src> {
|
|||||||
log::trace!("Condensing SET_LOCAL to binary math expression");
|
log::trace!("Condensing SET_LOCAL to binary math expression");
|
||||||
|
|
||||||
previous_instruction.set_a(register_index);
|
previous_instruction.set_a(register_index);
|
||||||
self.push_instruction(previous_instruction, self.current_position);
|
self.emit_instruction(previous_instruction, self.current_position);
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
|
||||||
self.push_instruction(previous_instruction, previous_position);
|
self.emit_instruction(previous_instruction, previous_position);
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::set_local(register, local_index),
|
Instruction::set_local(register, local_index),
|
||||||
start_position,
|
start_position,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::get_local(register, local_index),
|
Instruction::get_local(register, local_index),
|
||||||
self.previous_position,
|
self.previous_position,
|
||||||
);
|
);
|
||||||
@ -805,7 +805,7 @@ impl<'src> Parser<'src> {
|
|||||||
let actual_register = self.next_register() - 1;
|
let actual_register = self.next_register() - 1;
|
||||||
|
|
||||||
if expected_register < actual_register {
|
if expected_register < actual_register {
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::close(expected_register, actual_register),
|
Instruction::close(expected_register, actual_register),
|
||||||
self.current_position,
|
self.current_position,
|
||||||
);
|
);
|
||||||
@ -818,7 +818,7 @@ impl<'src> Parser<'src> {
|
|||||||
let end_register = to_register.saturating_sub(1);
|
let end_register = to_register.saturating_sub(1);
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_list(to_register, start_register, end_register),
|
Instruction::load_list(to_register, start_register, end_register),
|
||||||
Span(start, end),
|
Span(start, end),
|
||||||
);
|
);
|
||||||
@ -866,7 +866,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
load_constant.set_c_to_boolean(true);
|
load_constant.set_c_to_boolean(true);
|
||||||
|
|
||||||
self.push_instruction(load_constant, load_constant_position);
|
self.emit_instruction(load_constant, load_constant_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.allow(Token::Else)? {
|
if self.allow(Token::Else)? {
|
||||||
@ -937,7 +937,11 @@ impl<'src> Parser<'src> {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let parsed_expression = !self.current_statement.is_empty();
|
let parsed_expression = self
|
||||||
|
.current_statement
|
||||||
|
.last()
|
||||||
|
.map(|(instruction, _)| instruction.yields_value())
|
||||||
|
.unwrap_or(false);
|
||||||
let end_of_statement = matches!(
|
let end_of_statement = matches!(
|
||||||
self.current_token,
|
self.current_token,
|
||||||
Token::Eof | Token::RightCurlyBrace | Token::Semicolon
|
Token::Eof | Token::RightCurlyBrace | Token::Semicolon
|
||||||
@ -955,7 +959,7 @@ impl<'src> Parser<'src> {
|
|||||||
&& !has_semicolon
|
&& !has_semicolon
|
||||||
&& !returned
|
&& !returned
|
||||||
{
|
{
|
||||||
self.push_instruction(Instruction::r#return(true), self.current_position);
|
self.emit_instruction(Instruction::r#return(true), self.current_position);
|
||||||
self.commit_current_statement();
|
self.commit_current_statement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,7 +1011,7 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
|
|
||||||
self.push_instruction(Instruction::r#return(has_return_value), Span(start, end));
|
self.emit_instruction(Instruction::r#return(has_return_value), Span(start, end));
|
||||||
self.commit_current_statement();
|
self.commit_current_statement();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1055,7 +1059,7 @@ impl<'src> Parser<'src> {
|
|||||||
.declare_local(identifier, r#type, is_mutable, register, position)?;
|
.declare_local(identifier, r#type, is_mutable, register, position)?;
|
||||||
let register = self.next_register().saturating_sub(1);
|
let register = self.next_register().saturating_sub(1);
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::define_local(register, local_index, is_mutable),
|
Instruction::define_local(register, local_index, is_mutable),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
@ -1067,6 +1071,15 @@ impl<'src> Parser<'src> {
|
|||||||
fn parse_function(&mut self, _: Allowed) -> Result<(), ParseError> {
|
fn parse_function(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
let function_start = self.current_position.0;
|
let function_start = self.current_position.0;
|
||||||
let mut function_parser = Parser::new(self.lexer)?;
|
let mut function_parser = Parser::new(self.lexer)?;
|
||||||
|
let identifier = if let Token::Identifier(text) = function_parser.current_token {
|
||||||
|
let position = function_parser.current_position;
|
||||||
|
|
||||||
|
function_parser.advance()?;
|
||||||
|
|
||||||
|
Some((Identifier::new(text), position))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
function_parser.expect(Token::LeftParenthesis)?;
|
function_parser.expect(Token::LeftParenthesis)?;
|
||||||
|
|
||||||
@ -1161,11 +1174,30 @@ impl<'src> Parser<'src> {
|
|||||||
value_parameters,
|
value_parameters,
|
||||||
return_type,
|
return_type,
|
||||||
};
|
};
|
||||||
let function = Value::function(function_parser.chunk, function_type);
|
let function = Value::function(function_parser.chunk, function_type.clone());
|
||||||
let function_end = self.current_position.1;
|
let function_end = self.current_position.1;
|
||||||
|
|
||||||
self.lexer.skip_to(function_end);
|
self.lexer.skip_to(function_end);
|
||||||
self.emit_constant(function, Span(function_start, function_end))?;
|
|
||||||
|
if let Some((identifier, identifier_position)) = identifier {
|
||||||
|
let register = self.next_register();
|
||||||
|
let local_index = self.chunk.declare_local(
|
||||||
|
identifier,
|
||||||
|
Some(Type::Function(function_type)),
|
||||||
|
false,
|
||||||
|
register,
|
||||||
|
Span(function_start, function_end),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.emit_constant(function, Span(function_start, function_end))?;
|
||||||
|
self.emit_instruction(
|
||||||
|
Instruction::define_local(register, local_index, false),
|
||||||
|
identifier_position,
|
||||||
|
);
|
||||||
|
self.commit_current_statement();
|
||||||
|
} else {
|
||||||
|
self.emit_constant(function, Span(function_start, function_end))?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1196,10 +1228,10 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let end = self.current_position.1;
|
let end = self.current_position.1;
|
||||||
let argument_count = self.next_register() - function_register - 1;
|
|
||||||
let to_register = self.next_register();
|
let to_register = self.next_register();
|
||||||
|
let argument_count = to_register - function_register - 1;
|
||||||
|
|
||||||
self.push_instruction(
|
self.emit_instruction(
|
||||||
Instruction::call(to_register, function_register, argument_count),
|
Instruction::call(to_register, function_register, argument_count),
|
||||||
Span(start, end),
|
Span(start, end),
|
||||||
);
|
);
|
||||||
|
@ -346,6 +346,58 @@ fn function() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_declaration() {
|
||||||
|
let source = "fn add (a: int, b: int) -> int { a + b }";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0, false), Span(0, 40)),
|
||||||
|
(Instruction::define_local(0, 0, false), Span(3, 6)),
|
||||||
|
],
|
||||||
|
vec![Value::function(
|
||||||
|
Chunk::with_data(
|
||||||
|
vec![
|
||||||
|
(Instruction::add(2, 0, 1), Span(35, 36)),
|
||||||
|
(Instruction::r#return(true), Span(39, 40)),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
||||||
|
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
vec![Local::new(
|
||||||
|
Identifier::new("add"),
|
||||||
|
Some(Type::Function(FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: Some(vec![
|
||||||
|
(Identifier::new("a"), Type::Integer),
|
||||||
|
(Identifier::new("b"), Type::Integer)
|
||||||
|
]),
|
||||||
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
|
})),
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
),],
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(None));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_call() {
|
fn function_call() {
|
||||||
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
||||||
|
Loading…
Reference in New Issue
Block a user