Add new implicit return for end of file
This commit is contained in:
parent
7e4f6654a4
commit
ae6d3d7a82
@ -20,7 +20,7 @@ pub use instruction::Instruction;
|
||||
pub use lexer::{lex, LexError, Lexer};
|
||||
pub use native_function::{NativeFunction, NativeFunctionError};
|
||||
pub use operation::Operation;
|
||||
pub use parser::{parse, ParseError, Parser};
|
||||
pub use parser::{parse, ParseError};
|
||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||
pub use token::{Token, TokenKind, TokenOwned};
|
||||
pub use value::{Function, Primitive, Value, ValueError};
|
||||
|
@ -17,7 +17,7 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||
let lexer = Lexer::new(source);
|
||||
let mut parser = Parser::new(lexer).map_err(|error| DustError::Parse { error, source })?;
|
||||
|
||||
while !parser.is_eof() {
|
||||
loop {
|
||||
parser
|
||||
.parse_statement(Allowed {
|
||||
assignment: true,
|
||||
@ -25,13 +25,17 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||
implicit_return: true,
|
||||
})
|
||||
.map_err(|error| DustError::Parse { error, source })?;
|
||||
|
||||
if parser.is_eof() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(parser.finish())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize)]
|
||||
pub struct Parser<'src> {
|
||||
struct Parser<'src> {
|
||||
lexer: Lexer<'src>,
|
||||
chunk: Chunk,
|
||||
|
||||
@ -1256,6 +1260,10 @@ impl<'src> Parser<'src> {
|
||||
|
||||
fn parse_implicit_return(&mut self) -> Result<(), ParseError> {
|
||||
if !self.current_is_expression {
|
||||
if self.is_eof() {
|
||||
self.emit_instruction(Instruction::r#return(false), self.current_position);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -1273,6 +1281,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
if end_of_statement && !has_semicolon && !returned {
|
||||
self.emit_instruction(Instruction::r#return(true), self.current_position);
|
||||
} else if self.is_eof() {
|
||||
self.emit_instruction(Instruction::r#return(false), self.current_position);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -92,7 +92,7 @@ impl Vm {
|
||||
self.set(to_register, value, position)?;
|
||||
|
||||
if jump {
|
||||
self.jump_to_ip(self.ip + 1);
|
||||
self.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LoadConstant => {
|
||||
@ -103,7 +103,7 @@ impl Vm {
|
||||
self.set_constant(to_register, from_constant, position)?;
|
||||
|
||||
if jump {
|
||||
self.jump_to_ip(self.ip + 1);
|
||||
self.ip += 1
|
||||
}
|
||||
}
|
||||
Operation::LoadList => {
|
||||
@ -252,7 +252,7 @@ impl Vm {
|
||||
self.ip - jump_distance as usize
|
||||
};
|
||||
|
||||
self.jump_to_ip(new_ip);
|
||||
self.ip = new_ip;
|
||||
}
|
||||
}
|
||||
Operation::Less => {
|
||||
@ -288,7 +288,7 @@ impl Vm {
|
||||
self.ip - jump_distance as usize
|
||||
};
|
||||
|
||||
self.jump_to_ip(new_ip);
|
||||
self.ip = new_ip;
|
||||
}
|
||||
}
|
||||
Operation::LessEqual => {
|
||||
@ -325,7 +325,7 @@ impl Vm {
|
||||
self.ip - jump_distance as usize
|
||||
};
|
||||
|
||||
self.jump_to_ip(new_ip);
|
||||
self.ip = new_ip;
|
||||
}
|
||||
}
|
||||
Operation::Negate => {
|
||||
@ -360,8 +360,7 @@ impl Vm {
|
||||
} else {
|
||||
self.ip - jump_distance as usize - 1
|
||||
};
|
||||
|
||||
self.jump_to_ip(new_ip);
|
||||
self.ip = new_ip;
|
||||
}
|
||||
Operation::Call => {
|
||||
let to_register = instruction.a();
|
||||
@ -429,24 +428,6 @@ impl Vm {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn jump_to_ip(&mut self, new_ip: usize) {
|
||||
let final_index = self.chunk.len() - 1;
|
||||
|
||||
if new_ip > final_index {
|
||||
let last_operation = self
|
||||
.chunk
|
||||
.instructions()
|
||||
.last()
|
||||
.map(|(instruction, _)| instruction.operation());
|
||||
|
||||
if let Some(Operation::Return) = last_operation {
|
||||
self.ip = final_index;
|
||||
}
|
||||
} else {
|
||||
self.ip = new_ip;
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, to_register: u8, value: Value, position: Span) -> Result<(), VmError> {
|
||||
let length = self.stack.len();
|
||||
self.last_assigned_register = Some(to_register);
|
||||
@ -632,6 +613,10 @@ impl Vm {
|
||||
}
|
||||
|
||||
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
|
||||
if self.ip >= self.chunk.len() {
|
||||
self.ip = self.chunk.len() - 1;
|
||||
}
|
||||
|
||||
let current = self.chunk.get_instruction(self.ip, position)?;
|
||||
|
||||
self.ip += 1;
|
||||
|
@ -308,7 +308,7 @@ fn if_else_true() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expression_false() {
|
||||
fn if_false() {
|
||||
let source = "if 1 == 2 { 2 }";
|
||||
|
||||
assert_eq!(
|
||||
@ -324,6 +324,7 @@ fn if_expression_false() {
|
||||
),
|
||||
(Instruction::jump(1, true), Span(5, 7)),
|
||||
(Instruction::load_constant(0, 2, false), Span(12, 13)),
|
||||
(Instruction::r#return(false), Span(15, 15))
|
||||
],
|
||||
vec![Value::integer(1), Value::integer(2), Value::integer(2)],
|
||||
vec![]
|
||||
@ -334,7 +335,7 @@ fn if_expression_false() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expression_true() {
|
||||
fn if_true() {
|
||||
let source = "if 1 == 1 { 2 }";
|
||||
|
||||
assert_eq!(
|
||||
@ -350,6 +351,7 @@ fn if_expression_true() {
|
||||
),
|
||||
(Instruction::jump(1, true), Span(5, 7)),
|
||||
(Instruction::load_constant(0, 2, false), Span(12, 13)),
|
||||
(Instruction::r#return(false), Span(15, 15))
|
||||
],
|
||||
vec![Value::integer(1), Value::integer(1), Value::integer(2)],
|
||||
vec![]
|
||||
|
@ -77,6 +77,7 @@ fn block_scope() {
|
||||
(Instruction::define_local(3, 3, false), Span(125, 126)),
|
||||
(Instruction::load_constant(4, 4, false), Span(158, 159)),
|
||||
(Instruction::define_local(4, 4, false), Span(154, 155)),
|
||||
(Instruction::r#return(false), Span(165, 165))
|
||||
],
|
||||
vec![
|
||||
Value::integer(0),
|
||||
@ -129,6 +130,7 @@ fn define_local() {
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(8, 10)),
|
||||
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
||||
(Instruction::r#return(false), Span(11, 11))
|
||||
],
|
||||
vec![Value::integer(42)],
|
||||
vec![Local::new(Identifier::new("x"), None, false, 0, 0)]
|
||||
@ -195,7 +197,12 @@ fn empty() {
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(None, vec![], vec![], vec![]))
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
vec![(Instruction::r#return(false), Span(0, 0))],
|
||||
vec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
@ -262,6 +269,7 @@ fn function_declaration() {
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 40)),
|
||||
(Instruction::define_local(0, 0, false), Span(3, 6)),
|
||||
(Instruction::r#return(false), Span(40, 40))
|
||||
],
|
||||
vec![Value::function(
|
||||
Chunk::with_data(
|
||||
|
@ -15,6 +15,7 @@ fn panic() {
|
||||
Instruction::call_native(2, NativeFunction::Panic, 2),
|
||||
Span(0, 27)
|
||||
),
|
||||
(Instruction::r#return(false), Span(27, 27))
|
||||
],
|
||||
vec![Value::string("Goodbye world!"), Value::integer(42)],
|
||||
vec![]
|
||||
|
Loading…
Reference in New Issue
Block a user