Skip to content

Commit 2931db3

Browse files
committed
feat: add modules to ast and change architecture
1 parent 673e287 commit 2931db3

10 files changed

Lines changed: 688 additions & 214 deletions

File tree

examples/modules/main.simf

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
pub use temp::funcs::get_five;
1+
//pub use temp::funcs::{get_five, Smth};
2+
3+
pub fn temp() {
4+
let a: u32 = 33;
5+
}
26

37
fn seven() -> u32 {
48
7
59
}
610

711
fn main() {
8-
let five: u32 = dbg!(get_five());
9-
let seven: u32 = dbg!(seven());
12+
let smth: u32 = seven();
13+
//assert!(jet::eq_32(get_five(), seven()));
1014
}

examples/modules/temp/funcs.simf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub type Smth = u32;
2+
13
pub fn get_five() -> u32 {
24
5
35
}

src/ast.rs

Lines changed: 97 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ use miniscript::iter::{Tree, TreeLike};
99
use simplicity::jet::Elements;
1010

1111
use crate::debug::{CallTracker, DebugSymbols, TrackedCallName};
12+
use crate::driver::ProgramResolutions;
1213
use crate::error::{Error, RichError, Span, WithSpan};
1314
use crate::num::{NonZeroPow2Usize, Pow2Usize};
14-
use crate::parse::{MatchPattern, UseDecl, Visibility};
15+
use crate::parse::MatchPattern;
1516
use crate::pattern::Pattern;
1617
use crate::str::{AliasName, FunctionName, Identifier, ModuleName, WitnessName};
1718
use crate::types::{
1819
AliasedType, ResolvedType, StructuralType, TypeConstructible, TypeDeconstructible, UIntType,
1920
};
2021
use crate::value::{UIntValue, Value};
2122
use crate::witness::{Parameters, WitnessTypes, WitnessValues};
22-
use crate::{impl_eq_hash, parse};
23+
use crate::{SourceName, driver, impl_eq_hash, parse};
2324

2425
/// A program consists of the main function.
2526
///
@@ -73,8 +74,6 @@ pub enum Item {
7374
TypeAlias,
7475
/// A function.
7576
Function(Function),
76-
/// A use declaration
77-
Use(UseDecl),
7877
/// A module, which is ignored.
7978
Module,
8079
}
@@ -307,7 +306,6 @@ pub enum CallName {
307306
/// Definition of a custom function.
308307
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
309308
pub struct CustomFunction {
310-
visibility: Visibility,
311309
params: Arc<[FunctionParam]>,
312310
body: Arc<Expression>,
313311
}
@@ -525,6 +523,10 @@ impl TreeLike for ExprTree<'_> {
525523
/// 4. Resolving calls to custom functions
526524
#[derive(Clone, Debug, Eq, PartialEq, Default)]
527525
struct Scope {
526+
resolutions: ProgramResolutions,
527+
paths: Arc<[SourceName]>,
528+
file_id: usize, // ID of the file from which the function is called.
529+
528530
variables: Vec<HashMap<Identifier, ResolvedType>>,
529531
aliases: HashMap<AliasName, ResolvedType>,
530532
parameters: HashMap<WitnessName, ResolvedType>,
@@ -535,6 +537,26 @@ struct Scope {
535537
}
536538

537539
impl Scope {
540+
pub fn new(resolutions: ProgramResolutions, paths: Arc<[SourceName]>) -> Self {
541+
Self {
542+
resolutions,
543+
paths,
544+
file_id: 0,
545+
variables: Vec::new(),
546+
aliases: HashMap::new(),
547+
parameters: HashMap::new(),
548+
witnesses: HashMap::new(),
549+
functions: HashMap::new(),
550+
is_main: false,
551+
call_tracker: CallTracker::default(),
552+
}
553+
}
554+
555+
/// Access to current function file id.
556+
pub fn file_id(&self) -> usize {
557+
self.file_id
558+
}
559+
538560
/// Check if the current scope is topmost.
539561
pub fn is_topmost(&self) -> bool {
540562
self.variables.is_empty()
@@ -545,6 +567,11 @@ impl Scope {
545567
self.variables.push(HashMap::new());
546568
}
547569

570+
pub fn push_function_scope(&mut self, file_id: usize) {
571+
self.push_scope();
572+
self.file_id = file_id;
573+
}
574+
548575
/// Push the scope of the main function onto the stack.
549576
///
550577
/// ## Panics
@@ -567,6 +594,11 @@ impl Scope {
567594
self.variables.pop().expect("Stack is empty");
568595
}
569596

597+
pub fn pop_function_scope(&mut self, previous_file_id: usize) {
598+
self.pop_scope();
599+
self.file_id = previous_file_id;
600+
}
601+
570602
/// Pop the scope of the main function from the stack.
571603
///
572604
/// ## Panics
@@ -693,11 +725,51 @@ impl Scope {
693725
}
694726
}
695727

696-
/// Get the definition of a custom function.
697-
pub fn get_function(&self, name: &FunctionName) -> Option<&CustomFunction> {
698-
self.functions.get(name)
728+
/// Get the definition of a custom function with visibility and existence checks.
729+
///
730+
/// # Errors
731+
///
732+
/// - `Error::FileNotFound`: The specified file_id does not exist in the resolutions.
733+
/// - `Error::FunctionUndefined`: The function is not found in the file's scope OR not defined globally.
734+
/// - `Error::FunctionIsPrivate`: The function exists but is private (and thus not accessible).
735+
736+
// TODO: Add errors later
737+
pub fn get_function(
738+
&self,
739+
name: &FunctionName,
740+
) -> Result<&CustomFunction, Error> {
741+
// The order of the errors is important!
742+
let function = self.functions
743+
.get(name)
744+
.ok_or_else(|| Error::FunctionUndefined(name.clone()))?;
745+
746+
let source_name = self.paths[self.file_id].clone();
747+
748+
let file_scope = match source_name {
749+
SourceName::Real(path) => {
750+
self.resolutions
751+
.get(self.file_id)
752+
.ok_or(Error::FileNotFound(path))?
753+
},
754+
SourceName::Virtual(_) => {
755+
return Ok(function);
756+
}
757+
};
758+
759+
let identifier: Identifier = name.clone().into();
760+
761+
if file_scope.contains_key(&identifier) {
762+
Ok(function)
763+
} else {
764+
Err(Error::FunctionIsPrivate(name.clone()))
765+
}
699766
}
700767

768+
/// Get the definition of a custom function.
769+
// pub fn get_function(&self, name: &FunctionName) -> Option<&CustomFunction> {
770+
// self.functions.get(name)
771+
// }
772+
701773
/// Track a call expression with its span.
702774
pub fn track_call<S: AsRef<Span>>(&mut self, span: &S, name: TrackedCallName) {
703775
self.call_tracker.track_call(*span.as_ref(), name);
@@ -718,9 +790,10 @@ trait AbstractSyntaxTree: Sized {
718790
}
719791

720792
impl Program {
721-
pub fn analyze(from: &parse::Program) -> Result<Self, RichError> {
793+
// TODO: Add visibility check inside program
794+
pub fn analyze(from: &driver::Program) -> Result<Self, RichError> {
722795
let unit = ResolvedType::unit();
723-
let mut scope = Scope::default();
796+
let mut scope = Scope::new(Arc::from(from.resolutions()), Arc::from(from.paths()));
724797
let items = from
725798
.items()
726799
.iter()
@@ -746,103 +819,37 @@ impl Program {
746819
}
747820

748821
impl AbstractSyntaxTree for Item {
749-
type From = parse::Item;
822+
type From = driver::Item;
750823

751824
fn analyze(from: &Self::From, ty: &ResolvedType, scope: &mut Scope) -> Result<Self, RichError> {
752825
assert!(ty.is_unit(), "Items cannot return anything");
753826
assert!(scope.is_topmost(), "Items live in the topmost scope only");
754827

755828
match from {
756-
parse::Item::TypeAlias(alias) => {
829+
driver::Item::TypeAlias(alias) => {
757830
scope
758831
.insert_alias(alias.name().clone(), alias.ty().clone())
759832
.with_span(alias)?;
760833
Ok(Self::TypeAlias)
761834
}
762-
parse::Item::Function(function) => {
835+
driver::Item::Function(function) => {
763836
Function::analyze(function, ty, scope).map(Self::Function)
764837
}
765-
parse::Item::Use(_) => {
766-
println!("WARN: Skipping use declaration (not implemented yet)");
767-
Ok(Self::Module)
768-
//todo!()
769-
//Use::analyze(use_declaration).map(Self::Use)
770-
}
771-
parse::Item::Module => Ok(Self::Module),
838+
driver::Item::Module => Ok(Self::Module),
772839
}
773840
}
774841
}
775842

776843
impl AbstractSyntaxTree for Function {
777-
type From = parse::Function;
778-
779-
fn analyze(from: &Self::From, ty: &ResolvedType, scope: &mut Scope) -> Result<Self, RichError> {
780-
assert!(ty.is_unit(), "Function definitions cannot return anything");
781-
assert!(scope.is_topmost(), "Items live in the topmost scope only");
782-
783-
if from.name().as_inner() != "main" {
784-
let visibility = from.visibility().clone();
785-
let params = from
786-
.params()
787-
.iter()
788-
.map(|param| {
789-
let identifier = param.identifier().clone();
790-
let ty = scope.resolve(param.ty())?;
791-
Ok(FunctionParam { identifier, ty })
792-
})
793-
.collect::<Result<Arc<[FunctionParam]>, Error>>()
794-
.with_span(from)?;
795-
let ret = from
796-
.ret()
797-
.as_ref()
798-
.map(|aliased| scope.resolve(aliased).with_span(from))
799-
.transpose()?
800-
.unwrap_or_else(ResolvedType::unit);
801-
scope.push_scope();
802-
for param in params.iter() {
803-
scope.insert_variable(param.identifier().clone(), param.ty().clone());
804-
}
805-
let body = Expression::analyze(from.body(), &ret, scope).map(Arc::new)?;
806-
scope.pop_scope();
807-
debug_assert!(scope.is_topmost());
808-
let function = CustomFunction {
809-
visibility,
810-
params,
811-
body,
812-
};
813-
scope
814-
.insert_function(from.name().clone(), function)
815-
.with_span(from)?;
816-
817-
return Ok(Self::Custom);
818-
}
819-
820-
if !from.params().is_empty() {
821-
return Err(Error::MainNoInputs).with_span(from);
822-
}
823-
if let Some(aliased) = from.ret() {
824-
let resolved = scope.resolve(aliased).with_span(from)?;
825-
if !resolved.is_unit() {
826-
return Err(Error::MainNoOutput).with_span(from);
827-
}
828-
}
829-
830-
scope.push_main_scope();
831-
let body = Expression::analyze(from.body(), ty, scope)?;
832-
scope.pop_main_scope();
833-
Ok(Self::Main(body))
834-
}
835-
}
836-
837-
/*
838-
impl AbstractSyntaxTree for UseDecl {
839-
type From = parse::UseDecl;
844+
type From = driver::Function;
840845

841846
fn analyze(from: &Self::From, ty: &ResolvedType, scope: &mut Scope) -> Result<Self, RichError> {
842847
assert!(ty.is_unit(), "Function definitions cannot return anything");
843848
assert!(scope.is_topmost(), "Items live in the topmost scope only");
849+
let previous_file_id = scope.file_id();
844850

845851
if from.name().as_inner() != "main" {
852+
let file_id = from.file_id();
846853
let params = from
847854
.params()
848855
.iter()
@@ -859,12 +866,12 @@ impl AbstractSyntaxTree for UseDecl {
859866
.map(|aliased| scope.resolve(aliased).with_span(from))
860867
.transpose()?
861868
.unwrap_or_else(ResolvedType::unit);
862-
scope.push_scope();
869+
scope.push_function_scope(file_id);
863870
for param in params.iter() {
864871
scope.insert_variable(param.identifier().clone(), param.ty().clone());
865872
}
866873
let body = Expression::analyze(from.body(), &ret, scope).map(Arc::new)?;
867-
scope.pop_scope();
874+
scope.pop_function_scope(previous_file_id);
868875
debug_assert!(scope.is_topmost());
869876
let function = CustomFunction { params, body };
870877
scope
@@ -890,7 +897,6 @@ impl AbstractSyntaxTree for UseDecl {
890897
Ok(Self::Main(body))
891898
}
892899
}
893-
*/
894900

895901
impl AbstractSyntaxTree for Statement {
896902
type From = parse::Statement;
@@ -1361,6 +1367,8 @@ impl AbstractSyntaxTree for CallName {
13611367
_ty: &ResolvedType,
13621368
scope: &mut Scope,
13631369
) -> Result<Self, RichError> {
1370+
println!("_ty: {:#?}", _ty);
1371+
println!("Scope: {:#?}", scope);
13641372
match from.name() {
13651373
parse::CallName::Jet(name) => match Elements::from_str(name.as_inner()) {
13661374
Ok(Elements::CheckSigVerify | Elements::Verify) | Err(_) => {
@@ -1390,13 +1398,11 @@ impl AbstractSyntaxTree for CallName {
13901398
.get_function(name)
13911399
.cloned()
13921400
.map(Self::Custom)
1393-
.ok_or(Error::FunctionUndefined(name.clone()))
13941401
.with_span(from),
13951402
parse::CallName::ArrayFold(name, size) => {
13961403
let function = scope
13971404
.get_function(name)
13981405
.cloned()
1399-
.ok_or(Error::FunctionUndefined(name.clone()))
14001406
.with_span(from)?;
14011407
// A function that is used in a array fold has the signature:
14021408
// fn f(element: E, accumulator: A) -> A
@@ -1411,7 +1417,6 @@ impl AbstractSyntaxTree for CallName {
14111417
let function = scope
14121418
.get_function(name)
14131419
.cloned()
1414-
.ok_or(Error::FunctionUndefined(name.clone()))
14151420
.with_span(from)?;
14161421
// A function that is used in a list fold has the signature:
14171422
// fn f(element: E, accumulator: A) -> A
@@ -1426,7 +1431,6 @@ impl AbstractSyntaxTree for CallName {
14261431
let function = scope
14271432
.get_function(name)
14281433
.cloned()
1429-
.ok_or(Error::FunctionUndefined(name.clone()))
14301434
.with_span(from)?;
14311435
// A function that is used in a for-while loop has the signature:
14321436
// fn f(accumulator: A, readonly_context: C, counter: u{N}) -> Either<B, A>
@@ -1503,6 +1507,9 @@ fn analyze_named_module(
15031507
from: &parse::ModuleProgram,
15041508
) -> Result<HashMap<WitnessName, Value>, RichError> {
15051509
let unit = ResolvedType::unit();
1510+
1511+
// IMPORTANT! If modules allow imports, then we need to consider
1512+
// passing the resolution conetxt by calling `Scope::new(resolutions)`
15061513
let mut scope = Scope::default();
15071514
let items = from
15081515
.items()

0 commit comments

Comments
 (0)