Skip to content

Commit 44c3ced

Browse files
committed
Block-level scoping (#92) and variable manager (#88)
1 parent 55ce53e commit 44c3ced

File tree

14 files changed

+572
-265
lines changed

14 files changed

+572
-265
lines changed

crates/lean_compiler/src/a_simplify_lang.rs

Lines changed: 245 additions & 25 deletions
Large diffs are not rendered by default.

crates/lean_compiler/src/b_compile_intermediate.rs

Lines changed: 183 additions & 216 deletions
Large diffs are not rendered by default.

crates/lean_compiler/src/grammar.pest

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ return_count = { "->" ~ number }
1616

1717
// Statements
1818
statement = {
19+
forward_declaration |
1920
single_assignment |
2021
array_assign |
2122
if_statement |
@@ -34,6 +35,8 @@ return_statement = { "return" ~ (tuple_expression)? ~ ";" }
3435
break_statement = { "break" ~ ";" }
3536
continue_statement = { "continue" ~ ";" }
3637

38+
forward_declaration = { "var" ~ identifier ~ ";" }
39+
3740
single_assignment = { identifier ~ "=" ~ expression ~ ";" }
3841

3942
array_assign = { identifier ~ "[" ~ expression ~ "]" ~ "=" ~ expression ~ ";" }

crates/lean_compiler/src/lang.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use lean_vm::*;
22
use multilinear_toolkit::prelude::*;
33
use p3_util::log2_ceil_usize;
4-
use std::collections::BTreeMap;
4+
use std::collections::{BTreeMap, BTreeSet};
55
use std::fmt::{Display, Formatter};
66
use utils::ToUsize;
77

@@ -307,6 +307,9 @@ pub enum Line {
307307
value: Expression,
308308
arms: Vec<(usize, Vec<Self>)>,
309309
},
310+
ForwardDeclaration {
311+
var: Var,
312+
},
310313
Assignment {
311314
var: Var,
312315
value: Expression,
@@ -378,6 +381,30 @@ pub enum Line {
378381
location: SourceLineNumber,
379382
},
380383
}
384+
385+
/// A context specifying which variables are in scope.
386+
pub struct Context {
387+
/// A list of lexical scopes, innermost scope last.
388+
pub scopes: Vec<Scope>,
389+
}
390+
391+
impl Context {
392+
pub fn defines(&self, var: &Var) -> bool {
393+
for scope in self.scopes.iter() {
394+
if scope.vars.contains(var) {
395+
return true;
396+
}
397+
}
398+
false
399+
}
400+
}
401+
402+
#[derive(Default)]
403+
pub struct Scope {
404+
/// A set of declared variables.
405+
pub vars: BTreeSet<Var>,
406+
}
407+
381408
impl Display for Expression {
382409
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
383410
match self {
@@ -418,6 +445,9 @@ impl Line {
418445
.join("\n");
419446
format!("match {value} {{\n{arms_str}\n{spaces}}}")
420447
}
448+
Self::ForwardDeclaration { var } => {
449+
format!("var {var}")
450+
}
421451
Self::Assignment { var, value } => {
422452
format!("{var} = {value}")
423453
}

crates/lean_compiler/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn compile_program(program: String) -> Bytecode {
1616
let (parsed_program, function_locations) = parse_program(&program).unwrap();
1717
// println!("Parsed program: {}", parsed_program.to_string());
1818
let simple_program = simplify_program(parsed_program);
19-
// println!("Simplified program: {}", simple_program.to_string());
19+
// println!("Simplified program: {}", simple_program);
2020
let intermediate_bytecode = compile_to_intermediate_bytecode(simple_program).unwrap();
2121
// println!("Intermediate Bytecode:\n\n{}", intermediate_bytecode.to_string());
2222

crates/lean_compiler/src/parser/parsers/statement.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl Parse<Line> for StatementParser {
1919
let inner = next_inner_pair(&mut pair.into_inner(), "statement body")?;
2020

2121
match inner.as_rule() {
22+
Rule::forward_declaration => ForwardDeclarationParser::parse(inner, ctx),
2223
Rule::single_assignment => AssignmentParser::parse(inner, ctx),
2324
Rule::array_assign => ArrayAssignParser::parse(inner, ctx),
2425
Rule::if_statement => IfStatementParser::parse(inner, ctx),
@@ -35,6 +36,17 @@ impl Parse<Line> for StatementParser {
3536
}
3637
}
3738

39+
/// Parser for forward declarations of variables.
40+
pub struct ForwardDeclarationParser;
41+
42+
impl Parse<Line> for ForwardDeclarationParser {
43+
fn parse(pair: ParsePair<'_>, _ctx: &mut ParseContext) -> ParseResult<Line> {
44+
let mut inner = pair.into_inner();
45+
let var = next_inner_pair(&mut inner, "variable name")?.as_str().to_string();
46+
Ok(Line::ForwardDeclaration { var })
47+
}
48+
}
49+
3850
/// Parser for variable assignments.
3951
pub struct AssignmentParser;
4052

crates/lean_compiler/tests/test_compiler.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,26 @@ fn test_inlined() {
381381
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
382382
}
383383

384+
#[test]
385+
fn test_inlined_2() {
386+
let program = r#"
387+
fn main() {
388+
b = is_one();
389+
c = b;
390+
return;
391+
}
392+
393+
fn is_one() inline -> 1 {
394+
if 1 {
395+
return 1;
396+
} else {
397+
return 0;
398+
}
399+
}
400+
"#;
401+
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
402+
}
403+
384404
#[test]
385405
fn test_match() {
386406
let program = r#"
@@ -433,6 +453,29 @@ fn test_match() {
433453
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
434454
}
435455

456+
#[test]
457+
fn test_match_shrink() {
458+
let program = r#"
459+
fn main() {
460+
match 1 {
461+
0 => {
462+
y = 90;
463+
}
464+
1 => {
465+
y = 10;
466+
z = func_2(y);
467+
}
468+
}
469+
return;
470+
}
471+
472+
fn func_2(x) inline -> 1 {
473+
return x * x;
474+
}
475+
"#;
476+
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
477+
}
478+
436479
// #[test]
437480
// fn inline_bug_mre() {
438481
// let program = r#"
@@ -523,3 +566,26 @@ fn test_nested_inline_functions() {
523566

524567
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
525568
}
569+
570+
#[test]
571+
fn test_const_and_nonconst_malloc_sharing_name() {
572+
let program = r#"
573+
fn main() {
574+
f(1);
575+
return;
576+
}
577+
578+
fn f(n) {
579+
if 0 == 0 {
580+
res = malloc(2);
581+
res[1] = 0;
582+
return;
583+
} else {
584+
res = malloc(n * 1);
585+
return;
586+
}
587+
}
588+
"#;
589+
590+
compile_and_run(program.to_string(), (&[], &[]), DEFAULT_NO_VEC_RUNTIME_MEMORY, false);
591+
}

crates/lean_vm/src/diagnostics/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ pub enum RunnerError {
2525
#[error("Computation invalid: {0} != {1}")]
2626
NotEqual(F, F),
2727

28-
#[error("Undefined memory access")]
29-
UndefinedMemory,
28+
#[error("Undefined memory access: {0}")]
29+
UndefinedMemory(usize),
3030

3131
#[error("Program counter out of bounds")]
3232
PCOutOfBounds,

crates/lean_vm/src/execution/memory.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ impl Memory {
2525
///
2626
/// Returns an error if the address is uninitialized
2727
pub fn get(&self, index: usize) -> Result<F, RunnerError> {
28-
self.0.get(index).copied().flatten().ok_or(RunnerError::UndefinedMemory)
28+
self.0
29+
.get(index)
30+
.copied()
31+
.flatten()
32+
.ok_or(RunnerError::UndefinedMemory(index))
2933
}
3034

3135
/// Sets a value at a memory address

crates/lean_vm/src/execution/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn test_basic_memory_operations() {
1313
assert_eq!(memory.get(5).unwrap(), F::from_usize(42));
1414

1515
// Test undefined memory access
16-
assert!(matches!(memory.get(1), Err(RunnerError::UndefinedMemory)));
16+
assert!(matches!(memory.get(1), Err(RunnerError::UndefinedMemory(1))));
1717
}
1818

1919
#[test]

0 commit comments

Comments
 (0)