Rework how scopes work to support excluding sibling scopes
This commit is contained in:
parent
0dcfcd5375
commit
8c72e921dc
@ -1,6 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env::current_exe,
|
env::current_exe,
|
||||||
fmt::{self, Debug, Display},
|
fmt::{self, Debug, Display},
|
||||||
|
rc::Weak,
|
||||||
};
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
@ -14,7 +15,8 @@ pub struct Chunk {
|
|||||||
instructions: Vec<(Instruction, Span)>,
|
instructions: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Value>,
|
constants: Vec<Value>,
|
||||||
locals: Vec<Local>,
|
locals: Vec<Local>,
|
||||||
scope_depth: usize,
|
current_scope: Scope,
|
||||||
|
block_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
@ -24,7 +26,8 @@ impl Chunk {
|
|||||||
instructions: Vec::new(),
|
instructions: Vec::new(),
|
||||||
constants: Vec::new(),
|
constants: Vec::new(),
|
||||||
locals: Vec::new(),
|
locals: Vec::new(),
|
||||||
scope_depth: 0,
|
current_scope: Scope::default(),
|
||||||
|
block_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +42,8 @@ impl Chunk {
|
|||||||
instructions,
|
instructions,
|
||||||
constants,
|
constants,
|
||||||
locals,
|
locals,
|
||||||
scope_depth: 0,
|
current_scope: Scope::default(),
|
||||||
|
block_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,8 +91,8 @@ impl Chunk {
|
|||||||
&mut self.locals
|
&mut self.locals
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope_depth(&self) -> usize {
|
pub fn current_scope(&self) -> Scope {
|
||||||
self.scope_depth
|
self.current_scope
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_constant(&self, index: u8) -> Option<&Value> {
|
pub fn get_constant(&self, index: u8) -> Option<&Value> {
|
||||||
@ -118,11 +122,19 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_scope(&mut self) {
|
pub fn begin_scope(&mut self) {
|
||||||
self.scope_depth += 1;
|
self.current_scope.depth += 1;
|
||||||
|
self.current_scope.block = self.block_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_scope(&mut self) {
|
pub fn end_scope(&mut self) {
|
||||||
self.scope_depth -= 1;
|
self.current_scope.depth -= 1;
|
||||||
|
|
||||||
|
if self.current_scope.depth == 0 {
|
||||||
|
self.block_count += 1;
|
||||||
|
self.current_scope.block = 0;
|
||||||
|
} else {
|
||||||
|
self.current_scope.block = self.block_count;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassembler(&self) -> ChunkDisassembler {
|
pub fn disassembler(&self) -> ChunkDisassembler {
|
||||||
@ -163,7 +175,7 @@ pub struct Local {
|
|||||||
pub identifier_index: u8,
|
pub identifier_index: u8,
|
||||||
pub r#type: Option<Type>,
|
pub r#type: Option<Type>,
|
||||||
pub is_mutable: bool,
|
pub is_mutable: bool,
|
||||||
pub depth: usize,
|
pub scope: Scope,
|
||||||
pub register_index: u8,
|
pub register_index: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,19 +184,39 @@ impl Local {
|
|||||||
identifier_index: u8,
|
identifier_index: u8,
|
||||||
r#type: Option<Type>,
|
r#type: Option<Type>,
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
depth: usize,
|
scope: Scope,
|
||||||
register_index: u8,
|
register_index: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
depth,
|
scope,
|
||||||
register_index,
|
register_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
|
pub struct Scope {
|
||||||
|
/// The level of block nesting.
|
||||||
|
pub depth: usize,
|
||||||
|
/// The nth top-level block in the chunk.
|
||||||
|
pub block: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn new(depth: usize, block: usize) -> Self {
|
||||||
|
Self { depth, block }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Scope {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.depth, self.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ChunkDisassembler<'a> {
|
pub struct ChunkDisassembler<'a> {
|
||||||
chunk: &'a Chunk,
|
chunk: &'a Chunk,
|
||||||
source: Option<&'a str>,
|
source: Option<&'a str>,
|
||||||
@ -207,7 +239,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
const LOCAL_HEADER: [&'static str; 4] = [
|
const LOCAL_HEADER: [&'static str; 4] = [
|
||||||
"Locals",
|
"Locals",
|
||||||
"------",
|
"------",
|
||||||
"INDEX IDENTIFIER TYPE MUTABLE DEPTH REGISTER",
|
"INDEX IDENTIFIER TYPE MUTABLE SCOPE REGISTER",
|
||||||
"----- ---------- -------- ------- ----- --------",
|
"----- ---------- -------- ------- ----- --------",
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -429,7 +461,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
Local {
|
Local {
|
||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
depth,
|
scope: depth,
|
||||||
register_index,
|
register_index,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
},
|
},
|
||||||
|
@ -454,7 +454,7 @@ impl Instruction {
|
|||||||
};
|
};
|
||||||
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
|
let mutable_display = if self.c_as_boolean() { "mut" } else { "" };
|
||||||
|
|
||||||
format!("L{local_index} = R{to_register} {mutable_display} {identifier_display}")
|
format!("R{to_register} = L{local_index} {mutable_display} {identifier_display}")
|
||||||
}
|
}
|
||||||
Operation::GetLocal => {
|
Operation::GetLocal => {
|
||||||
let local_index = self.b();
|
let local_index = self.b();
|
||||||
|
@ -11,7 +11,7 @@ mod r#type;
|
|||||||
mod value;
|
mod value;
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|
||||||
pub use chunk::{Chunk, ChunkDisassembler, Local};
|
pub use chunk::{Chunk, ChunkDisassembler, Local, Scope};
|
||||||
pub use dust_error::{AnnotatedError, DustError};
|
pub use dust_error::{AnnotatedError, DustError};
|
||||||
pub use formatter::{format, Formatter};
|
pub use formatter::{format, Formatter};
|
||||||
pub use instruction::Instruction;
|
pub use instruction::Instruction;
|
||||||
|
@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnnotatedError, Chunk, DustError, FunctionType, Instruction, LexError, Lexer, Local,
|
AnnotatedError, Chunk, DustError, FunctionType, Instruction, LexError, Lexer, Local,
|
||||||
NativeFunction, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
|
NativeFunction, Operation, Scope, Span, Token, TokenKind, TokenOwned, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||||
@ -149,11 +149,11 @@ impl<'src> Parser<'src> {
|
|||||||
identifier: &str,
|
identifier: &str,
|
||||||
r#type: Option<Type>,
|
r#type: Option<Type>,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
|
scope: Scope,
|
||||||
register_index: u8,
|
register_index: u8,
|
||||||
) -> (u8, u8) {
|
) -> (u8, u8) {
|
||||||
log::debug!("Declare local {identifier}");
|
log::debug!("Declare local {identifier}");
|
||||||
|
|
||||||
let scope_depth = self.chunk.scope_depth();
|
|
||||||
let identifier = Value::string(identifier);
|
let identifier = Value::string(identifier);
|
||||||
let identifier_index = self.chunk.push_or_get_constant(identifier);
|
let identifier_index = self.chunk.push_or_get_constant(identifier);
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ impl<'src> Parser<'src> {
|
|||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
is_mutable,
|
is_mutable,
|
||||||
scope_depth,
|
scope,
|
||||||
register_index,
|
register_index,
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -823,9 +823,10 @@ impl<'src> Parser<'src> {
|
|||||||
} else if let Some(name) = self.chunk.name() {
|
} else if let Some(name) = self.chunk.name() {
|
||||||
if name.as_str() == text {
|
if name.as_str() == text {
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
let scope = self.chunk.current_scope();
|
||||||
|
|
||||||
self.emit_instruction(Instruction::load_self(register), start_position);
|
self.emit_instruction(Instruction::load_self(register), start_position);
|
||||||
self.declare_local(text, None, false, register);
|
self.declare_local(text, None, false, scope, register);
|
||||||
|
|
||||||
self.current_is_expression = true;
|
self.current_is_expression = true;
|
||||||
|
|
||||||
@ -1317,6 +1318,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
|
let scope = self.chunk.current_scope();
|
||||||
let is_mutable = self.allow(Token::Mut)?;
|
let is_mutable = self.allow(Token::Mut)?;
|
||||||
let position = self.current_position;
|
let position = self.current_position;
|
||||||
let identifier = if let Token::Identifier(text) = self.current_token {
|
let identifier = if let Token::Identifier(text) = self.current_token {
|
||||||
@ -1344,7 +1346,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.expect(Token::Equal)?;
|
self.expect(Token::Equal)?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let (local_index, _) = self.declare_local(identifier, r#type, is_mutable, register);
|
let (local_index, _) = self.declare_local(identifier, r#type, is_mutable, scope, register);
|
||||||
let register = self.next_register().saturating_sub(1);
|
let register = self.next_register().saturating_sub(1);
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
@ -1403,10 +1405,12 @@ impl<'src> Parser<'src> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|values| values.len() as u8)
|
.map(|values| values.len() as u8)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
let scope = function_parser.chunk.current_scope();
|
||||||
let (_, identifier_index) = function_parser.declare_local(
|
let (_, identifier_index) = function_parser.declare_local(
|
||||||
parameter,
|
parameter,
|
||||||
Some(r#type.clone()),
|
Some(r#type.clone()),
|
||||||
is_mutable,
|
is_mutable,
|
||||||
|
scope,
|
||||||
register,
|
register,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1456,10 +1460,12 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
if let Some((identifier, identifier_position)) = identifier {
|
if let Some((identifier, identifier_position)) = identifier {
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
|
let scope = self.chunk.current_scope();
|
||||||
let (local_index, _) = self.declare_local(
|
let (local_index, _) = self.declare_local(
|
||||||
identifier,
|
identifier,
|
||||||
Some(Type::Function(function_type)),
|
Some(Type::Function(function_type)),
|
||||||
false,
|
false,
|
||||||
|
scope,
|
||||||
register,
|
register,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ fn equality_assignment_long() {
|
|||||||
(Instruction::r#return(true), Span(44, 44)),
|
(Instruction::r#return(true), Span(44, 44)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::string("a")],
|
vec![Value::integer(4), Value::string("a")],
|
||||||
vec![Local::new(1, None, false, 0, 0)]
|
vec![Local::new(1, None, false, Scope { depth: 0, block: 0 }, 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ fn equality_assignment_short() {
|
|||||||
(Instruction::r#return(true), Span(16, 16)),
|
(Instruction::r#return(true), Span(16, 16)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::string("a")],
|
vec![Value::integer(4), Value::string("a")],
|
||||||
vec![Local::new(1, None, false, 0, 0)]
|
vec![Local::new(1, None, false, Scope::default(), 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ fn if_else_assigment() {
|
|||||||
Value::integer(42),
|
Value::integer(42),
|
||||||
Value::string("a")
|
Value::string("a")
|
||||||
],
|
],
|
||||||
vec![Local::new(5, None, false, 0, 0)]
|
vec![Local::new(5, None, false, Scope::default(), 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ fn add_assign() {
|
|||||||
(Instruction::r#return(true), Span(24, 24))
|
(Instruction::r#return(true), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::string("a"), Value::integer(2)],
|
vec![Value::integer(1), Value::string("a"), Value::integer(2)],
|
||||||
vec![Local::new(1, None, true, 0, 0)]
|
vec![Local::new(1, None, true, Scope::default(), 0)]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ fn define_local() {
|
|||||||
(Instruction::r#return(false), Span(11, 11))
|
(Instruction::r#return(false), Span(11, 11))
|
||||||
],
|
],
|
||||||
vec![Value::integer(42), Value::string("x")],
|
vec![Value::integer(42), Value::string("x")],
|
||||||
vec![Local::new(1, None, false, 0, 0)]
|
vec![Local::new(1, None, false, Scope::default(), 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ fn divide_assign() {
|
|||||||
(Instruction::r#return(true), Span(24, 24))
|
(Instruction::r#return(true), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::string("a")],
|
vec![Value::integer(2), Value::string("a")],
|
||||||
vec![Local::new(1, None, true, 0, 0)]
|
vec![Local::new(1, None, true, Scope::default(), 0)]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ fn multiply_assign() {
|
|||||||
(Instruction::r#return(true), Span(23, 23))
|
(Instruction::r#return(true), Span(23, 23))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::string("a"), Value::integer(3)],
|
vec![Value::integer(2), Value::string("a"), Value::integer(3)],
|
||||||
vec![Local::new(1, None, true, 0, 0),]
|
vec![Local::new(1, None, true, Scope::default(), 0),]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -453,7 +453,7 @@ fn set_local() {
|
|||||||
(Instruction::r#return(true), Span(25, 25)),
|
(Instruction::r#return(true), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(41), Value::string("x"), Value::integer(42)],
|
vec![Value::integer(41), Value::string("x"), Value::integer(42)],
|
||||||
vec![Local::new(1, None, true, 0, 0)]
|
vec![Local::new(1, None, true, Scope::default(), 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -504,7 +504,7 @@ fn subtract_assign() {
|
|||||||
(Instruction::r#return(true), Span(25, 25)),
|
(Instruction::r#return(true), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42), Value::string("x"), Value::integer(2)],
|
vec![Value::integer(42), Value::string("x"), Value::integer(2)],
|
||||||
vec![Local::new(1, None, true, 0, 0)]
|
vec![Local::new(1, None, true, Scope::default(), 0)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -532,8 +532,8 @@ fn variable_and() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, None, false, 0, 0),
|
Local::new(0, None, false, Scope::default(), 0),
|
||||||
Local::new(1, None, false, 0, 1),
|
Local::new(1, None, false, Scope::default(), 1),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
@ -568,7 +568,7 @@ fn r#while() {
|
|||||||
Value::integer(5),
|
Value::integer(5),
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
],
|
],
|
||||||
vec![Local::new(1, None, true, 0, 0),]
|
vec![Local::new(1, None, true, Scope::default(), 0),]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ fn function() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, 0, 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
||||||
Local::new(1, Some(Type::Integer), false, 0, 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -53,8 +53,8 @@ fn function_call() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, 0, 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
||||||
Local::new(1, Some(Type::Integer), false, 0, 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -97,8 +97,8 @@ fn function_declaration() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b")],
|
vec![Value::string("a"), Value::string("b")],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, 0, 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
||||||
Local::new(1, Some(Type::Integer), false, 0, 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -116,7 +116,7 @@ fn function_declaration() {
|
|||||||
return_type: Some(Box::new(Type::Integer)),
|
return_type: Some(Box::new(Type::Integer)),
|
||||||
})),
|
})),
|
||||||
false,
|
false,
|
||||||
0,
|
Scope::default(),
|
||||||
0
|
0
|
||||||
),],
|
),],
|
||||||
)),
|
)),
|
||||||
|
@ -55,11 +55,11 @@ fn block_scope() {
|
|||||||
Value::string("e"),
|
Value::string("e"),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Local::new(1, None, false, 0, 0),
|
Local::new(1, None, false, Scope::new(0, 0), 0),
|
||||||
Local::new(3, None, false, 1, 1),
|
Local::new(3, None, false, Scope::new(1, 0), 1),
|
||||||
Local::new(5, None, false, 2, 2),
|
Local::new(5, None, false, Scope::new(2, 0), 2),
|
||||||
Local::new(7, None, false, 1, 3),
|
Local::new(7, None, false, Scope::new(1, 0), 3),
|
||||||
Local::new(8, None, false, 0, 4),
|
Local::new(8, None, false, Scope::new(0, 0), 4),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@ -67,6 +67,81 @@ fn block_scope() {
|
|||||||
assert_eq!(run(source), Ok(None));
|
assert_eq!(run(source), Ok(None));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multiple_block_scopes() {
|
||||||
|
let source = "
|
||||||
|
let a = 0;
|
||||||
|
{
|
||||||
|
let b = 42;
|
||||||
|
{
|
||||||
|
let c = 1;
|
||||||
|
}
|
||||||
|
let d = 2;
|
||||||
|
}
|
||||||
|
let q = 42;
|
||||||
|
{
|
||||||
|
let b = 42;
|
||||||
|
{
|
||||||
|
let c = 1;
|
||||||
|
}
|
||||||
|
let d = 2;
|
||||||
|
}
|
||||||
|
let e = 1;
|
||||||
|
";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0, false), Span(17, 18)),
|
||||||
|
(Instruction::define_local(0, 0, false), Span(13, 14)),
|
||||||
|
(Instruction::load_constant(1, 2, false), Span(50, 52)),
|
||||||
|
(Instruction::define_local(1, 1, false), Span(46, 47)),
|
||||||
|
(Instruction::load_constant(2, 4, false), Span(92, 93)),
|
||||||
|
(Instruction::define_local(2, 2, false), Span(88, 89)),
|
||||||
|
(Instruction::load_constant(3, 6, false), Span(129, 130)),
|
||||||
|
(Instruction::define_local(3, 3, false), Span(125, 126)),
|
||||||
|
(Instruction::load_constant(4, 2, false), Span(158, 160)),
|
||||||
|
(Instruction::define_local(4, 4, false), Span(154, 155)),
|
||||||
|
(Instruction::load_constant(5, 2, false), Span(192, 194)),
|
||||||
|
(Instruction::define_local(5, 5, false), Span(188, 189)),
|
||||||
|
(Instruction::load_constant(6, 4, false), Span(234, 235)),
|
||||||
|
(Instruction::define_local(6, 6, false), Span(230, 231)),
|
||||||
|
(Instruction::load_constant(7, 6, false), Span(271, 272)),
|
||||||
|
(Instruction::define_local(7, 7, false), Span(267, 268)),
|
||||||
|
(Instruction::load_constant(8, 4, false), Span(300, 301)),
|
||||||
|
(Instruction::define_local(8, 8, false), Span(296, 297)),
|
||||||
|
(Instruction::r#return(false), Span(307, 307))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
Value::integer(0),
|
||||||
|
Value::string("a"),
|
||||||
|
Value::integer(42),
|
||||||
|
Value::string("b"),
|
||||||
|
Value::integer(1),
|
||||||
|
Value::string("c"),
|
||||||
|
Value::integer(2),
|
||||||
|
Value::string("d"),
|
||||||
|
Value::string("q"),
|
||||||
|
Value::string("e"),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
Local::new(1, None, false, Scope::new(0, 0), 0),
|
||||||
|
Local::new(3, None, false, Scope::new(1, 0), 1),
|
||||||
|
Local::new(5, None, false, Scope::new(2, 0), 2),
|
||||||
|
Local::new(7, None, false, Scope::new(1, 0), 3),
|
||||||
|
Local::new(8, None, false, Scope::new(0, 0), 4),
|
||||||
|
Local::new(3, None, false, Scope::new(1, 1), 5),
|
||||||
|
Local::new(5, None, false, Scope::new(2, 1), 6),
|
||||||
|
Local::new(7, None, false, Scope::new(1, 1), 7),
|
||||||
|
Local::new(9, None, false, Scope::new(0, 0), 8),
|
||||||
|
]
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(None));
|
||||||
|
}
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn disallow_access_to_child_scope() {
|
// fn disallow_access_to_child_scope() {
|
||||||
// let source = r#"
|
// let source = r#"
|
||||||
|
Loading…
Reference in New Issue
Block a user