Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions examples/modules.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use example::of::my::file;
pub use another::file::*;
pub use some::list::{of, items};

pub fn get_five() -> u32 {
5
}

fn main() {
let five: u32 = dbg!(get_five());
assert!(jet::eq_32(five, 5));
}
9 changes: 9 additions & 0 deletions examples/modules/main.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//pub use temp::get_five;

fn get_five() -> u32 {
7
}

fn main() {
let five: u32 = get_five();
}
3 changes: 3 additions & 0 deletions examples/modules/temp/get_five.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn get_five() -> u32 {
5
}
68 changes: 67 additions & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use simplicity::jet::Elements;
use crate::debug::{CallTracker, DebugSymbols, TrackedCallName};
use crate::error::{Error, RichError, Span, WithSpan};
use crate::num::{NonZeroPow2Usize, Pow2Usize};
use crate::parse::MatchPattern;
use crate::parse::{MatchPattern, UseDecl};
use crate::pattern::Pattern;
use crate::str::{AliasName, FunctionName, Identifier, ModuleName, WitnessName};
use crate::types::{
Expand Down Expand Up @@ -73,6 +73,8 @@ pub enum Item {
TypeAlias,
/// A function.
Function(Function),
/// A use declaration
Use(UseDecl),
/// A module, which is ignored.
Module,
}
Expand Down Expand Up @@ -759,6 +761,12 @@ impl AbstractSyntaxTree for Item {
parse::Item::Function(function) => {
Function::analyze(function, ty, scope).map(Self::Function)
}
parse::Item::Use(_) => {
println!("WARN: Skipping use declaration (not implemented yet)");
Ok(Self::Module)
//todo!()
//Use::analyze(use_declaration).map(Self::Use)
}
parse::Item::Module => Ok(Self::Module),
}
}
Expand Down Expand Up @@ -820,6 +828,64 @@ impl AbstractSyntaxTree for Function {
}
}

/*
impl AbstractSyntaxTree for UseDecl {
type From = parse::UseDecl;

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

if from.name().as_inner() != "main" {
let params = from
.params()
.iter()
.map(|param| {
let identifier = param.identifier().clone();
let ty = scope.resolve(param.ty())?;
Ok(FunctionParam { identifier, ty })
})
.collect::<Result<Arc<[FunctionParam]>, Error>>()
.with_span(from)?;
let ret = from
.ret()
.as_ref()
.map(|aliased| scope.resolve(aliased).with_span(from))
.transpose()?
.unwrap_or_else(ResolvedType::unit);
scope.push_scope();
for param in params.iter() {
scope.insert_variable(param.identifier().clone(), param.ty().clone());
}
let body = Expression::analyze(from.body(), &ret, scope).map(Arc::new)?;
scope.pop_scope();
debug_assert!(scope.is_topmost());
let function = CustomFunction { params, body };
scope
.insert_function(from.name().clone(), function)
.with_span(from)?;

return Ok(Self::Custom);
}

if !from.params().is_empty() {
return Err(Error::MainNoInputs).with_span(from);
}
if let Some(aliased) = from.ret() {
let resolved = scope.resolve(aliased).with_span(from)?;
if !resolved.is_unit() {
return Err(Error::MainNoOutput).with_span(from);
}
}

scope.push_main_scope();
let body = Expression::analyze(from.body(), ty, scope)?;
scope.pop_main_scope();
Ok(Self::Main(body))
}
}
*/

impl AbstractSyntaxTree for Statement {
type From = parse::Statement;

Expand Down
9 changes: 9 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub type Tokens<'src> = Vec<(Token<'src>, crate::error::Span)>;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Token<'src> {
// Keywords
Pub,
Use,
As,
Fn,
Let,
Type,
Expand Down Expand Up @@ -63,6 +66,9 @@ pub enum Token<'src> {
impl<'src> fmt::Display for Token<'src> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Token::Pub => write!(f, "pub"),
Token::Use => write!(f, "use"),
Token::As => write!(f, "as"),
Token::Fn => write!(f, "fn"),
Token::Let => write!(f, "let"),
Token::Type => write!(f, "type"),
Expand Down Expand Up @@ -134,6 +140,9 @@ pub fn lexer<'src>(
choice((just("assert!"), just("panic!"), just("dbg!"), just("list!"))).map(Token::Macro);

let keyword = text::ident().map(|s| match s {
"pub" => Token::Pub,
"use" => Token::Use,
"as" => Token::As,
"fn" => Token::Fn,
"let" => Token::Let,
"type" => Token::Type,
Expand Down
24 changes: 20 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub mod types;
pub mod value;
mod witness;

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;

use simplicity::jet::elements::ElementsEnv;
Expand All @@ -36,6 +38,12 @@ pub use crate::types::ResolvedType;
pub use crate::value::Value;
pub use crate::witness::{Arguments, Parameters, WitnessTypes, WitnessValues};

#[derive(Debug, Clone)]
pub struct LibResolver {
pub alias: String,
pub directory: PathBuf,
}

/// The template of a SimplicityHL program.
///
/// A template has parameterized values that need to be supplied with arguments.
Expand All @@ -51,11 +59,16 @@ impl TemplateProgram {
/// ## Errors
///
/// The string is not a valid SimplicityHL program.
pub fn new<Str: Into<Arc<str>>>(s: Str) -> Result<Self, String> {
pub fn new<Str: Into<Arc<str>>>(library_map: &HashMap<String, PathBuf>, s: Str) -> Result<Self, String> {
let file = s.into();
let mut error_handler = ErrorCollector::new(Arc::clone(&file));
let parse_program = parse::Program::parse_from_str_with_errors(&file, &mut error_handler);

if let Some(program) = parse_program {
if !library_map.is_empty() {
// TODO: Implement with ast
}

let ast_program = ast::Program::analyze(&program).with_file(Arc::clone(&file))?;
Ok(Self {
simfony: ast_program,
Expand Down Expand Up @@ -115,11 +128,12 @@ impl CompiledProgram {
/// - [`TemplateProgram::new`]
/// - [`TemplateProgram::instantiate`]
pub fn new<Str: Into<Arc<str>>>(
library_map: &HashMap<String, PathBuf>,
s: Str,
arguments: Arguments,
include_debug_symbols: bool,
) -> Result<Self, String> {
TemplateProgram::new(s)
TemplateProgram::new(library_map, s)
.and_then(|template| template.instantiate(arguments, include_debug_symbols))
}

Expand Down Expand Up @@ -186,12 +200,13 @@ impl SatisfiedProgram {
/// - [`TemplateProgram::instantiate`]
/// - [`CompiledProgram::satisfy`]
pub fn new<Str: Into<Arc<str>>>(
library_map: &HashMap<String, PathBuf>,
s: Str,
arguments: Arguments,
witness_values: WitnessValues,
include_debug_symbols: bool,
) -> Result<Self, String> {
let compiled = CompiledProgram::new(s, arguments, include_debug_symbols)?;
let compiled = CompiledProgram::new(library_map, s, arguments, include_debug_symbols)?;
compiled.satisfy(witness_values)
}

Expand Down Expand Up @@ -294,7 +309,7 @@ pub(crate) mod tests {
}

pub fn template_text(program_text: Cow<str>) -> Self {
let program = match TemplateProgram::new(program_text.as_ref()) {
let program = match TemplateProgram::new(&HashMap::new(), program_text.as_ref()) {
Ok(x) => x,
Err(error) => panic!("{error}"),
};
Expand Down Expand Up @@ -631,6 +646,7 @@ fn main() {
}
"#;
match SatisfiedProgram::new(
&HashMap::new(),
prog_text,
Arguments::default(),
WitnessValues::default(),
Expand Down
27 changes: 25 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use base64::engine::general_purpose::STANDARD;
use clap::{Arg, ArgAction, Command};

use simplicityhl::{Arguments, CompiledProgram};
use std::{env, fmt};
use std::{collections::HashMap, env, fmt};

#[cfg_attr(feature = "serde", derive(serde::Serialize))]
/// The compilation output.
Expand Down Expand Up @@ -41,6 +41,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.action(ArgAction::Set)
.help("SimplicityHL program file to build"),
)
.arg(
Arg::new("library")
.long("lib")
.short('L')
.value_name("ALIAS=PATH")
.action(ArgAction::Append)
.help("Link a library with an alias (e.g., --lib math=./libs/math)"),
)
.arg(
Arg::new("wit_file")
.value_name("WITNESS_FILE")
Expand Down Expand Up @@ -68,9 +76,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let prog_text = std::fs::read_to_string(prog_path).map_err(|e| e.to_string())?;
let include_debug_symbols = matches.get_flag("debug");
let output_json = matches.get_flag("json");

let lib_args = matches.get_many::<String>("library").unwrap_or_default();

let library_map: HashMap<String, std::path::PathBuf> = lib_args
.map(|arg| {
let parts: Vec<&str> = arg.splitn(2, '=').collect();

if parts.len() != 2 {
eprintln!("Error: Library argument must be in format ALIAS=PATH, got '{}'", arg);
std::process::exit(1);
}

(parts[0].to_string(), std::path::PathBuf::from(parts[1]))
})
.collect();

let compiled =
match CompiledProgram::new(prog_text, Arguments::default(), include_debug_symbols) {
match CompiledProgram::new(&library_map, prog_text, Arguments::default(), include_debug_symbols) {
Ok(program) => program,
Err(e) => {
eprintln!("{}", e);
Expand Down
Loading