Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement main expressions #168

Merged
merged 1 commit into from
Mar 25, 2024
Merged
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
20 changes: 20 additions & 0 deletions app/src/cli/check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::path::PathBuf;

use query::{Database, File};

use crate::result::IOError;

#[derive(clap::Args)]
pub struct Args {
#[clap(value_parser, value_name = "FILE")]
filepath: PathBuf,
}

pub fn exec(cmd: Args) -> miette::Result<()> {
let mut db = Database::default();
let file = File::read(&cmd.filepath).map_err(IOError::from).map_err(miette::Report::from)?;
let view = db.add(file).query();
let _ = view.tst().map_err(|err| view.pretty_error(err))?;
println!("{} typechecked successfully!", cmd.filepath.display());
Ok(())
}
6 changes: 5 additions & 1 deletion app/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use clap::{Parser, Subcommand};

mod check;
mod format;
mod ignore_colors;
mod lift;
Expand All @@ -14,6 +15,7 @@ pub fn exec() -> miette::Result<()> {
typechecker::tracer::set_enabled(cli.trace);
match cli.command {
Run(args) => run::exec(args),
Check(args) => check::exec(args),
Fmt(args) => format::exec(args),
Texify(args) => texify::exec(args),
Xfunc(args) => xfunc::exec(args),
Expand All @@ -34,8 +36,10 @@ struct Cli {

#[derive(Subcommand)]
enum Command {
/// Run a source code file
/// Run the main expression of a file
Run(run::Args),
/// Typecheck a file
Check(check::Args),
/// Format a code file
Fmt(format::Args),
/// Render a code file as a latex document
Expand Down
15 changes: 12 additions & 3 deletions app/src/cli/run.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::path::PathBuf;

use miette::Diagnostic;
use thiserror::Error;

use printer::{ColorChoice, PrintExt, StandardStream};
use query::{Database, File};
use syntax::nf;
Expand All @@ -16,10 +19,11 @@ pub fn exec(cmd: Args) -> miette::Result<()> {
let mut db = Database::default();
let file = File::read(&cmd.filepath).map_err(IOError::from).map_err(miette::Report::from)?;
let view = db.add(file).query();

let nf = view.run().map_err(|err| view.pretty_error(err))?;
println!("{} typechecked successfully!", cmd.filepath.display());
if let Some(nf) = nf {
print_nf(&nf)
match nf {
Some(nf) => print_nf(&nf),
None => return Err(miette::Report::from(MainNotFound {})),
}
Ok(())
}
Expand All @@ -29,3 +33,8 @@ fn print_nf(nf: &nf::Nf) {
nf.print_colored(&Default::default(), &mut stream).expect("Failed to print to stdout");
println!();
}

#[derive(Error, Diagnostic, Debug)]
#[error("Main expression was not found")]
#[diagnostic(help("Main expressions must be called \"main\" and not take any arguments."))]
pub struct MainNotFound {}
5 changes: 2 additions & 3 deletions examples/vect.pol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ def Top.example1: Vec(2) {
Unit => Cons(1, 0, Cons(0, 0, Nil))
}

def Top.example2: Vec(4) {
Unit => Unit.example1.append(2, 2, Unit.example1)
let main : Vec(4) {
Unit.example1.append(2, 2, Unit.example1)
}

16 changes: 15 additions & 1 deletion lang/query/src/view/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::rc::Rc;

use super::DatabaseView;

use normalizer::normalize::Normalize;
use parser::cst;
use syntax::{nf, tst, ust};

Expand Down Expand Up @@ -33,7 +34,20 @@ impl<'a> DatabaseView<'a> {
}

pub fn run(&self) -> Result<Option<Rc<nf::Nf>>, Error> {
Ok(None)
let tst = self.tst()?;
let ust = tst.forget();

let main = ust.find_main();

match main {
Some(exp) => {
let nf = exp
.normalize_in_empty_env(&ust)
.map_err(|err| Error::Type(typechecker::TypeError::Eval(err)))?;
Ok(Some(nf))
}
None => Ok(None),
}
}

pub fn pretty_error(&self, err: Error) -> miette::Report {
Expand Down
22 changes: 22 additions & 0 deletions lang/syntax/src/trees/generic/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ pub struct Prg<P: Phase> {
pub decls: Decls<P>,
}

impl<P: Phase> Prg<P> {
pub fn find_main(&self) -> Option<Rc<Exp<P>>> {
let main_candidate = self.decls.map.get("main")?.get_main()?;
Some(main_candidate.body)
}
}

#[derive(Debug, Clone)]
pub struct Decls<P: Phase> {
/// Map from identifiers to declarations
Expand Down Expand Up @@ -76,6 +83,14 @@ impl<P: Phase> Decl<P> {
Decl::Let(_) => DeclKind::Let,
}
}

/// Returns whether the declaration is the "main" expression of the module.
pub fn get_main(&self) -> Option<Let<P>> {
match self {
Decl::Let(tl_let) => tl_let.is_main().then(|| tl_let.clone()),
_ => None,
}
}
}
impl<P: Phase> HasSpan for Decl<P> {
fn span(&self) -> Option<Span> {
Expand Down Expand Up @@ -194,6 +209,13 @@ pub struct Let<P: Phase> {
pub body: Rc<Exp<P>>,
}

impl<P: Phase> Let<P> {
/// Returns whether the declaration is the "main" expression of the module.
pub fn is_main(&self) -> bool {
self.name == "main" && self.params.is_empty()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably forbid parameters on let bindings called main during lowering.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasoning: otherwise it is confusing for users because they will see the error message "main not found" but they have a main expression with a different signature.

}
}

#[derive(Debug, Clone, Derivative)]
#[derivative(Eq, PartialEq, Hash)]
pub struct Match<P: Phase> {
Expand Down