work out some initial direction for code gen

This commit is contained in:
Kasey White 2022-10-27 03:12:45 -04:00 committed by Lucas
parent 51302f1730
commit ffa78e4c30
9 changed files with 464 additions and 148 deletions

View File

@ -53,9 +53,9 @@ impl UntypedModule {
pub fn dependencies(&self) -> Vec<(String, Span)> { pub fn dependencies(&self) -> Vec<(String, Span)> {
self.definitions() self.definitions()
.flat_map(|def| { .flat_map(|def| {
if let Definition::Use { if let Definition::Use(Use {
location, module, .. location, module, ..
} = def }) = def
{ {
Some((module.join("/"), *location)) Some((module.join("/"), *location))
} else { } else {
@ -69,58 +69,73 @@ impl UntypedModule {
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>; pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>;
pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>; pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>;
#[derive(Debug, Clone, PartialEq)]
pub struct Function<T, Expr> {
pub arguments: Vec<Arg<T>>,
pub body: Expr,
pub doc: Option<String>,
pub location: Span,
pub name: String,
pub public: bool,
pub return_annotation: Option<Annotation>,
pub return_type: T,
pub end_position: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TypeAlias<T> {
pub alias: String,
pub annotation: Annotation,
pub doc: Option<String>,
pub location: Span,
pub parameters: Vec<String>,
pub public: bool,
pub tipo: T,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DataType<T> {
pub constructors: Vec<RecordConstructor<T>>,
pub doc: Option<String>,
pub location: Span,
pub name: String,
pub opaque: bool,
pub parameters: Vec<String>,
pub public: bool,
pub typed_parameters: Vec<T>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Use<PackageName> {
pub as_name: Option<String>,
pub location: Span,
pub module: Vec<String>,
pub package: PackageName,
pub unqualified: Vec<UnqualifiedImport>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ModuleConstant<T, ConstantRecordTag> {
pub doc: Option<String>,
pub location: Span,
pub public: bool,
pub name: String,
pub annotation: Option<Annotation>,
pub value: Box<Constant<T, ConstantRecordTag>>,
pub tipo: T,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Definition<T, Expr, ConstantRecordTag, PackageName> { pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
Fn { Fn(Function<T, Expr>),
arguments: Vec<Arg<T>>,
body: Expr,
doc: Option<String>,
location: Span,
name: String,
public: bool,
return_annotation: Option<Annotation>,
return_type: T,
end_position: usize,
},
TypeAlias { TypeAlias(TypeAlias<T>),
alias: String,
annotation: Annotation,
doc: Option<String>,
location: Span,
parameters: Vec<String>,
public: bool,
tipo: T,
},
DataType { DataType(DataType<T>),
constructors: Vec<RecordConstructor<T>>,
doc: Option<String>,
location: Span,
name: String,
opaque: bool,
parameters: Vec<String>,
public: bool,
typed_parameters: Vec<T>,
},
Use { Use(Use<PackageName>),
as_name: Option<String>,
location: Span,
module: Vec<String>,
package: PackageName,
unqualified: Vec<UnqualifiedImport>,
},
ModuleConstant { ModuleConstant(ModuleConstant<T, ConstantRecordTag>),
doc: Option<String>,
location: Span,
public: bool,
name: String,
annotation: Option<Annotation>,
value: Box<Constant<T, ConstantRecordTag>>,
tipo: T,
},
} }
impl<A, B, C, E> Definition<A, B, C, E> { impl<A, B, C, E> Definition<A, B, C, E> {

View File

@ -119,12 +119,14 @@ pub fn import_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Par
.then(as_name); .then(as_name);
just(Token::Use).ignore_then(module_path).map_with_span( just(Token::Use).ignore_then(module_path).map_with_span(
|((module, unqualified), as_name), span| ast::UntypedDefinition::Use { |((module, unqualified), as_name), span| {
module, ast::UntypedDefinition::Use(ast::Use {
as_name, module,
unqualified: unqualified.unwrap_or_default(), as_name,
package: (), unqualified: unqualified.unwrap_or_default(),
location: span, package: (),
location: span,
})
}, },
) )
} }
@ -176,7 +178,7 @@ pub fn data_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
.then(type_name_with_args()) .then(type_name_with_args())
.then(choice((constructors, record_sugar))) .then(choice((constructors, record_sugar)))
.map_with_span(|((pub_opaque, (name, parameters)), constructors), span| { .map_with_span(|((pub_opaque, (name, parameters)), constructors), span| {
ast::UntypedDefinition::DataType { ast::UntypedDefinition::DataType(ast::DataType {
location: span, location: span,
constructors: constructors constructors: constructors
.into_iter() .into_iter()
@ -196,7 +198,7 @@ pub fn data_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
parameters: parameters.unwrap_or_default(), parameters: parameters.unwrap_or_default(),
public: pub_opaque.is_some(), public: pub_opaque.is_some(),
typed_parameters: vec![], typed_parameters: vec![],
} })
}) })
} }
@ -207,7 +209,7 @@ pub fn type_alias_parser() -> impl Parser<Token, ast::UntypedDefinition, Error =
.then_ignore(just(Token::Equal)) .then_ignore(just(Token::Equal))
.then(type_parser()) .then(type_parser())
.map_with_span(|((opt_pub, (alias, parameters)), annotation), span| { .map_with_span(|((opt_pub, (alias, parameters)), annotation), span| {
ast::UntypedDefinition::TypeAlias { ast::UntypedDefinition::TypeAlias(ast::TypeAlias {
alias, alias,
annotation, annotation,
doc: None, doc: None,
@ -215,7 +217,7 @@ pub fn type_alias_parser() -> impl Parser<Token, ast::UntypedDefinition, Error =
parameters: parameters.unwrap_or_default(), parameters: parameters.unwrap_or_default(),
public: opt_pub.is_some(), public: opt_pub.is_some(),
tipo: (), tipo: (),
} })
}) })
} }
@ -239,7 +241,7 @@ pub fn fn_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseEr
) )
.map_with_span( .map_with_span(
|((((opt_pub, name), (arguments, args_span)), return_annotation), body), span| { |((((opt_pub, name), (arguments, args_span)), return_annotation), body), span| {
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(ast::Function {
arguments, arguments,
body: body.unwrap_or(expr::UntypedExpr::Todo { body: body.unwrap_or(expr::UntypedExpr::Todo {
kind: TodoKind::EmptyFunction, kind: TodoKind::EmptyFunction,
@ -259,7 +261,7 @@ pub fn fn_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseEr
public: opt_pub.is_some(), public: opt_pub.is_some(),
return_annotation, return_annotation,
return_type: (), return_type: (),
} })
}, },
) )
} }

View File

@ -2,8 +2,9 @@ use chumsky::prelude::*;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use crate::{ use crate::{
ast::{self, Span}, ast::{self, DataType, Function, Span, TypeAlias, Use},
expr, parser, expr, lexer,
parser::module_parser,
}; };
#[test] #[test]
@ -116,14 +117,14 @@ fn module() {
name: "".to_string(), name: "".to_string(),
type_info: (), type_info: (),
definitions: vec![ definitions: vec![
ast::UntypedDefinition::Use { ast::UntypedDefinition::Use(Use {
location: Span::new((), 13..25), location: Span::new((), 13..25),
module: vec!["std".to_string(), "list".to_string()], module: vec!["std".to_string(), "list".to_string()],
as_name: None, as_name: None,
unqualified: vec![], unqualified: vec![],
package: (), package: (),
}, }),
ast::UntypedDefinition::Use { ast::UntypedDefinition::Use(Use {
location: Span::new((), 38..80), location: Span::new((), 38..80),
module: vec!["std".to_string(), "address".to_string()], module: vec!["std".to_string(), "address".to_string()],
as_name: None, as_name: None,
@ -142,15 +143,15 @@ fn module() {
} }
], ],
package: (), package: (),
}, }),
ast::UntypedDefinition::Use { ast::UntypedDefinition::Use(Use {
location: Span::new((), 93..108), location: Span::new((), 93..108),
module: vec!["std".to_string(), "tx".to_string()], module: vec!["std".to_string(), "tx".to_string()],
as_name: Some("t".to_string()), as_name: Some("t".to_string()),
unqualified: vec![], unqualified: vec![],
package: (), package: (),
}, }),
ast::UntypedDefinition::DataType { ast::UntypedDefinition::DataType(DataType {
location: Span::new((), 122..240), location: Span::new((), 122..240),
constructors: vec![ constructors: vec![
ast::RecordConstructor { ast::RecordConstructor {
@ -229,8 +230,8 @@ fn module() {
parameters: vec!["a".to_string(),], parameters: vec!["a".to_string(),],
public: false, public: false,
typed_parameters: vec![], typed_parameters: vec![],
}, }),
ast::UntypedDefinition::DataType { ast::UntypedDefinition::DataType(DataType {
location: Span::new((), 254..313), location: Span::new((), 254..313),
constructors: vec![ast::RecordConstructor { constructors: vec![ast::RecordConstructor {
location: Span::new((), 275..313), location: Span::new((), 275..313),
@ -254,8 +255,8 @@ fn module() {
parameters: vec![], parameters: vec![],
public: true, public: true,
typed_parameters: vec![], typed_parameters: vec![],
}, }),
ast::UntypedDefinition::TypeAlias { ast::UntypedDefinition::TypeAlias(TypeAlias {
alias: "Thing".to_string(), alias: "Thing".to_string(),
annotation: ast::Annotation::Constructor { annotation: ast::Annotation::Constructor {
location: Span::new((), 340..351), location: Span::new((), 340..351),
@ -273,8 +274,8 @@ fn module() {
parameters: vec![], parameters: vec![],
public: false, public: false,
tipo: (), tipo: (),
}, }),
ast::UntypedDefinition::TypeAlias { ast::UntypedDefinition::TypeAlias(TypeAlias {
alias: "Me".to_string(), alias: "Me".to_string(),
annotation: ast::Annotation::Constructor { annotation: ast::Annotation::Constructor {
location: Span::new((), 379..393), location: Span::new((), 379..393),
@ -292,8 +293,9 @@ fn module() {
parameters: vec![], parameters: vec![],
public: true, public: true,
tipo: (), tipo: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 0,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
name: "a".to_string(), name: "a".to_string(),
@ -326,9 +328,8 @@ fn module() {
arguments: vec![], arguments: vec![],
},), },),
return_type: (), return_type: (),
end_position: 466, }),
}, ast::UntypedDefinition::Fn(Function {
ast::UntypedDefinition::Fn {
end_position: 598, end_position: 598,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::NamedLabeled { arg_name: ast::ArgName::NamedLabeled {
@ -375,8 +376,8 @@ fn module() {
public: true, public: true,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 839, end_position: 839,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -480,8 +481,8 @@ fn module() {
public: true, public: true,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1238, end_position: 1238,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -647,8 +648,8 @@ fn module() {
public: true, public: true,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1377, end_position: 1377,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
@ -724,8 +725,8 @@ fn module() {
arguments: vec![], arguments: vec![],
},), },),
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1402, end_position: 1402,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Todo { body: expr::UntypedExpr::Todo {
@ -739,8 +740,8 @@ fn module() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1477, end_position: 1477,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -770,8 +771,8 @@ fn module() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1655, end_position: 1655,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
@ -912,8 +913,8 @@ fn module() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 1781, end_position: 1781,
arguments: vec![ arguments: vec![
ast::Arg { ast::Arg {
@ -978,8 +979,8 @@ fn module() {
arguments: vec![], arguments: vec![],
},), },),
return_type: (), return_type: (),
}, }),
ast::UntypedDefinition::Fn { ast::UntypedDefinition::Fn(Function {
end_position: 2049, end_position: 2049,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::If { body: expr::UntypedExpr::If {
@ -1054,7 +1055,7 @@ fn module() {
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
}, }),
] ]
}, },
); );

View File

@ -8,8 +8,9 @@ use itertools::Itertools;
use crate::{ use crate::{
ast::{ ast::{
Annotation, ArgName, CallArg, Definition, Pattern, RecordConstructor, RecordConstructorArg, Annotation, ArgName, CallArg, DataType, Definition, Function, ModuleConstant, Pattern,
Span, TypedDefinition, UnqualifiedImport, UntypedDefinition, PIPE_VARIABLE, RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition,
UnqualifiedImport, UntypedDefinition, Use, PIPE_VARIABLE,
}, },
builtins::{function, generic_var, unbound_var}, builtins::{function, generic_var, unbound_var},
tipo::fields::FieldMap, tipo::fields::FieldMap,
@ -186,7 +187,7 @@ impl<'a> Environment<'a> {
module_name: &String, module_name: &String,
) -> TypedDefinition { ) -> TypedDefinition {
match s { match s {
Definition::Fn { Definition::Fn(Function {
doc, doc,
location, location,
name, name,
@ -196,7 +197,7 @@ impl<'a> Environment<'a> {
return_annotation, return_annotation,
return_type, return_type,
end_position, end_position,
} => { }) => {
// Lookup the inferred function information // Lookup the inferred function information
let function = self let function = self
.get_variable(&name) .get_variable(&name)
@ -230,7 +231,7 @@ impl<'a> Environment<'a> {
}, },
); );
Definition::Fn { Definition::Fn(Function {
doc, doc,
location, location,
name, name,
@ -240,7 +241,7 @@ impl<'a> Environment<'a> {
return_type, return_type,
body, body,
end_position, end_position,
} })
} }
definition @ (Definition::TypeAlias { .. } definition @ (Definition::TypeAlias { .. }
@ -655,13 +656,13 @@ impl<'a> Environment<'a> {
pub fn register_import(&mut self, def: &UntypedDefinition) -> Result<(), Error> { pub fn register_import(&mut self, def: &UntypedDefinition) -> Result<(), Error> {
match def { match def {
Definition::Use { Definition::Use(Use {
module, module,
as_name, as_name,
unqualified, unqualified,
location, location,
.. ..
} => { }) => {
let name = module.join("/"); let name = module.join("/");
// Find imported module // Find imported module
@ -819,14 +820,14 @@ impl<'a> Environment<'a> {
names: &mut HashMap<&'a str, &'a Span>, names: &mut HashMap<&'a str, &'a Span>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match def { match def {
Definition::DataType { Definition::DataType(DataType {
name, name,
public, public,
parameters, parameters,
location, location,
constructors, constructors,
.. ..
} => { }) => {
assert_unique_type_name(names, name, location)?; assert_unique_type_name(names, name, location)?;
// Build a type from the type Annotation // Build a type from the type Annotation
@ -864,14 +865,14 @@ impl<'a> Environment<'a> {
} }
} }
Definition::TypeAlias { Definition::TypeAlias(TypeAlias {
location, location,
public, public,
parameters: args, parameters: args,
alias: name, alias: name,
annotation: resolved_type, annotation: resolved_type,
.. ..
} => { }) => {
assert_unique_type_name(names, name, location)?; assert_unique_type_name(names, name, location)?;
// Register the paramerterised types // Register the paramerterised types
@ -915,14 +916,14 @@ impl<'a> Environment<'a> {
names: &mut HashMap<&'a str, &'a Span>, names: &mut HashMap<&'a str, &'a Span>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match def { match def {
Definition::Fn { Definition::Fn(Function {
name, name,
arguments: args, arguments: args,
location, location,
return_annotation, return_annotation,
public, public,
.. ..
} => { }) => {
assert_unique_value_name(names, name, location)?; assert_unique_value_name(names, name, location)?;
self.ungeneralised_functions.insert(name.to_string()); self.ungeneralised_functions.insert(name.to_string());
@ -980,14 +981,14 @@ impl<'a> Environment<'a> {
} }
} }
Definition::DataType { Definition::DataType(DataType {
location, location,
public, public,
opaque, opaque,
name, name,
constructors, constructors,
.. ..
} => { }) => {
let mut hydrator = hydrators let mut hydrator = hydrators
.remove(name) .remove(name)
.expect("Could not find hydrator for register_values custom type"); .expect("Could not find hydrator for register_values custom type");
@ -1079,7 +1080,7 @@ impl<'a> Environment<'a> {
} }
} }
Definition::ModuleConstant { name, location, .. } => { Definition::ModuleConstant(ModuleConstant { name, location, .. }) => {
assert_unique_const_name(names, name, location)?; assert_unique_const_name(names, name, location)?;
} }

View File

@ -2,8 +2,9 @@ use std::collections::HashMap;
use crate::{ use crate::{
ast::{ ast::{
Definition, Layer, ModuleKind, RecordConstructor, RecordConstructorArg, TypedDefinition, DataType, Definition, Function, Layer, ModuleConstant, ModuleKind, RecordConstructor,
TypedModule, UntypedDefinition, UntypedModule, RecordConstructorArg, TypeAlias, TypedDefinition, TypedModule, UntypedDefinition,
UntypedModule, Use,
}, },
builtins::function, builtins::function,
parser::token::Token, parser::token::Token,
@ -142,7 +143,7 @@ fn infer_definition(
environment: &mut Environment<'_>, environment: &mut Environment<'_>,
) -> Result<TypedDefinition, Error> { ) -> Result<TypedDefinition, Error> {
match def { match def {
Definition::Fn { Definition::Fn(Function {
doc, doc,
location, location,
name, name,
@ -152,7 +153,7 @@ fn infer_definition(
return_annotation, return_annotation,
end_position, end_position,
.. ..
} => { }) => {
let preregistered_fn = environment let preregistered_fn = environment
.get_variable(&name) .get_variable(&name)
.expect("Could not find preregistered type for function"); .expect("Could not find preregistered type for function");
@ -217,7 +218,7 @@ fn infer_definition(
tipo tipo
}; };
Ok(Definition::Fn { Ok(Definition::Fn(Function {
doc, doc,
location, location,
name, name,
@ -229,10 +230,10 @@ fn infer_definition(
.expect("Could not find return type for fn"), .expect("Could not find return type for fn"),
body, body,
end_position, end_position,
}) }))
} }
Definition::TypeAlias { Definition::TypeAlias(TypeAlias {
doc, doc,
location, location,
public, public,
@ -240,14 +241,14 @@ fn infer_definition(
parameters, parameters,
annotation, annotation,
.. ..
} => { }) => {
let tipo = environment let tipo = environment
.get_type_constructor(&None, &alias, location) .get_type_constructor(&None, &alias, location)
.expect("Could not find existing type for type alias") .expect("Could not find existing type for type alias")
.tipo .tipo
.clone(); .clone();
Ok(Definition::TypeAlias { Ok(Definition::TypeAlias(TypeAlias {
doc, doc,
location, location,
public, public,
@ -255,10 +256,10 @@ fn infer_definition(
parameters, parameters,
annotation, annotation,
tipo, tipo,
}) }))
} }
Definition::DataType { Definition::DataType(DataType {
doc, doc,
location, location,
public, public,
@ -267,7 +268,7 @@ fn infer_definition(
parameters, parameters,
constructors, constructors,
.. ..
} => { }) => {
let constructors = constructors let constructors = constructors
.into_iter() .into_iter()
.map( .map(
@ -330,7 +331,7 @@ fn infer_definition(
.parameters .parameters
.clone(); .clone();
Ok(Definition::DataType { Ok(Definition::DataType(DataType {
doc, doc,
location, location,
public, public,
@ -339,16 +340,16 @@ fn infer_definition(
parameters, parameters,
constructors, constructors,
typed_parameters, typed_parameters,
}) }))
} }
Definition::Use { Definition::Use(Use {
location, location,
module, module,
as_name, as_name,
mut unqualified, mut unqualified,
.. ..
} => { }) => {
let name = module.join("/"); let name = module.join("/");
// Find imported module // Find imported module
@ -371,16 +372,16 @@ fn infer_definition(
} }
} }
Ok(Definition::Use { Ok(Definition::Use(Use {
location, location,
module, module,
as_name, as_name,
unqualified, unqualified,
package: module_info.package.clone(), package: module_info.package.clone(),
}) }))
} }
Definition::ModuleConstant { Definition::ModuleConstant(ModuleConstant {
doc, doc,
location, location,
name, name,
@ -388,7 +389,7 @@ fn infer_definition(
public, public,
value, value,
.. ..
} => { }) => {
let typed_expr = ExprTyper::new(environment).infer_const(&annotation, *value)?; let typed_expr = ExprTyper::new(environment).infer_const(&annotation, *value)?;
let tipo = typed_expr.tipo(); let tipo = typed_expr.tipo();
@ -411,7 +412,7 @@ fn infer_definition(
environment.init_usage(name.clone(), EntityKind::PrivateConstant, location); environment.init_usage(name.clone(), EntityKind::PrivateConstant, location);
} }
Ok(Definition::ModuleConstant { Ok(Definition::ModuleConstant(ModuleConstant {
doc, doc,
location, location,
name, name,
@ -419,7 +420,7 @@ fn infer_definition(
public, public,
value: Box::new(typed_expr), value: Box::new(typed_expr),
tipo, tipo,
}) }))
} }
} }
} }

View File

@ -2,6 +2,7 @@ use std::{
collections::HashMap, collections::HashMap,
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc,
}; };
pub mod config; pub mod config;
@ -10,16 +11,22 @@ pub mod format;
pub mod module; pub mod module;
use aiken_lang::{ use aiken_lang::{
ast::{Definition, ModuleKind}, ast::{Definition, Function, ModuleKind},
builtins, builtins,
expr::TypedExpr,
tipo::TypeInfo, tipo::TypeInfo,
IdGenerator, IdGenerator,
}; };
use uplc::{
ast::{Constant, Name, NamedDeBruijn, Program, Term, Unique},
builtins::DefaultFunction,
parser::interner::Interner,
};
use crate::{ use crate::{
config::Config, config::Config,
error::{Error, Warning}, error::{Error, Warning},
module::{CheckedModule, CheckedModules, ParsedModule, ParsedModules}, module::{self, CheckedModule, CheckedModules, ParsedModule, ParsedModules},
}; };
#[derive(Debug)] #[derive(Debug)]
@ -74,7 +81,7 @@ impl Project {
self.compile(false) self.compile(false)
} }
pub fn compile(&mut self, _uplc_gen: bool) -> Result<(), Error> { pub fn compile(&mut self, uplc_gen: bool) -> Result<(), Error> {
self.read_source_files()?; self.read_source_files()?;
let parsed_modules = self.parse_sources()?; let parsed_modules = self.parse_sources()?;
@ -83,7 +90,11 @@ impl Project {
let mut checked_modules = self.type_check(parsed_modules, processing_sequence)?; let mut checked_modules = self.type_check(parsed_modules, processing_sequence)?;
let _scripts = self.validate_scripts(&mut checked_modules)?; let scripts = self.validate_scripts(&mut checked_modules)?;
if uplc_gen {
self.code_gen(&scripts, &checked_modules)?;
}
Ok(()) Ok(())
} }
@ -240,13 +251,13 @@ impl Project {
scripts.push(module.clone()); scripts.push(module.clone());
for def in module.ast.definitions() { for def in module.ast.definitions() {
if let Definition::Fn { if let Definition::Fn(Function {
arguments, arguments,
location, location,
name, name,
return_type, return_type,
.. ..
} = def }) = def
{ {
if VALIDATOR_NAMES.contains(&name.as_str()) { if VALIDATOR_NAMES.contains(&name.as_str()) {
// validators must return a Bool // validators must return a Bool
@ -295,6 +306,286 @@ impl Project {
} }
} }
fn code_gen(
&mut self,
scripts: &[CheckedModule],
checked_modules: &CheckedModules,
) -> Result<Vec<Program<NamedDeBruijn>>, Error> {
let mut programs = Vec::new();
let mut uplc_function_holder = Vec::new();
let mut functions = HashMap::new();
let mut type_aliases = HashMap::new();
let mut data_types = HashMap::new();
let mut imports = HashMap::new();
let mut constants = HashMap::new();
for module in checked_modules.values() {
for def in module.ast.definitions() {
match def {
Definition::Fn(func) => {
functions.insert((module.name.clone(), func.name.clone()), func);
}
Definition::TypeAlias(ta) => {
type_aliases.insert((module.name.clone(), ta.alias.clone()), ta);
}
Definition::DataType(dt) => {
data_types.insert((module.name.clone(), dt.name.clone()), dt);
}
Definition::Use(import) => {
imports.insert((module.name.clone(), import.module.join("/")), import);
}
Definition::ModuleConstant(mc) => {
constants.insert((module.name.clone(), mc.name.clone()), mc);
}
}
}
}
for script in scripts {
for def in script.ast.definitions() {
if let Definition::Fn(Function {
arguments,
name,
body,
..
}) = def
{
if VALIDATOR_NAMES.contains(&name.as_str()) {
let type_info = self.module_types.get(&script.name).unwrap();
println!("{type_info:#?}");
let mut term = self.recurse_code_gen(
body,
scripts,
0,
&uplc_function_holder,
&functions,
&type_aliases,
&data_types,
&imports,
&constants,
);
for arg in arguments.iter().rev() {
term = Term::Lambda {
parameter_name: uplc::ast::Name {
text: arg
.arg_name
.get_variable_name()
.unwrap_or("_")
.to_string(),
unique: Unique::new(0),
},
body: Rc::new(term),
}
}
let mut program = Program {
version: (1, 0, 0),
term,
};
let mut interner = Interner::new();
interner.program(&mut program);
programs.push(program.try_into().unwrap());
}
}
}
}
Ok(programs)
}
fn recurse_code_gen(
&self,
body: &aiken_lang::expr::TypedExpr,
scripts: &[CheckedModule],
scope_level: i32,
uplc_function_holder: &Vec<Term<Name>>,
functions: &HashMap<
(String, String),
&Function<std::sync::Arc<aiken_lang::tipo::Type>, aiken_lang::expr::TypedExpr>,
>,
type_aliases: &HashMap<
(String, String),
&aiken_lang::ast::TypeAlias<std::sync::Arc<aiken_lang::tipo::Type>>,
>,
data_types: &HashMap<
(String, String),
&aiken_lang::ast::DataType<std::sync::Arc<aiken_lang::tipo::Type>>,
>,
imports: &HashMap<(String, String), &aiken_lang::ast::Use<String>>,
constants: &HashMap<
(String, String),
&aiken_lang::ast::ModuleConstant<std::sync::Arc<aiken_lang::tipo::Type>, String>,
>,
) -> Term<uplc::ast::Name> {
let terms = match body {
aiken_lang::expr::TypedExpr::Int { value, .. } => {
Term::Constant(Constant::Integer(value.parse::<i128>().unwrap()))
}
aiken_lang::expr::TypedExpr::String { value, .. } => {
Term::Constant(Constant::String(value.clone()))
}
aiken_lang::expr::TypedExpr::ByteArray { bytes, .. } => {
Term::Constant(Constant::ByteString(bytes.clone()))
}
aiken_lang::expr::TypedExpr::Sequence {
location,
expressions,
} => todo!(),
aiken_lang::expr::TypedExpr::Pipeline {
location,
expressions,
} => todo!(),
aiken_lang::expr::TypedExpr::Var {
location,
constructor,
name,
} => todo!(),
aiken_lang::expr::TypedExpr::Fn {
location,
tipo,
is_capture,
args,
body,
return_annotation,
} => todo!(),
aiken_lang::expr::TypedExpr::List {
location,
tipo,
elements,
tail,
} => todo!(),
aiken_lang::expr::TypedExpr::Call {
location,
tipo,
fun,
args,
} => todo!(),
aiken_lang::expr::TypedExpr::BinOp {
location,
tipo,
name,
left,
right,
} => todo!(),
aiken_lang::expr::TypedExpr::Assignment {
location,
tipo,
value,
pattern,
kind,
} => todo!(),
aiken_lang::expr::TypedExpr::Try {
location,
tipo,
value,
then,
pattern,
} => todo!(),
aiken_lang::expr::TypedExpr::When {
location,
tipo,
subjects,
clauses,
} => todo!(),
//if statements increase scope due to branching.
aiken_lang::expr::TypedExpr::If {
branches,
final_else,
..
} => {
let mut final_if_term = self.recurse_code_gen(
final_else,
scripts,
scope_level + 1,
uplc_function_holder,
functions,
type_aliases,
data_types,
imports,
constants,
);
for branch in branches {
// Need some scoping count to potentially replace condition with var since we should assume a condition
// may be repeated 3 + times or be large enough series of binops to warrant var replacement
let condition_term = self.recurse_code_gen(
&branch.condition,
scripts,
scope_level + 1, // Since this happens before branching. Maybe not increase scope level
uplc_function_holder,
functions,
type_aliases,
data_types,
imports,
constants,
);
let branch_term = self.recurse_code_gen(
&branch.body,
scripts,
scope_level + 1,
uplc_function_holder,
functions,
type_aliases,
data_types,
imports,
constants,
);
final_if_term = Term::Apply {
function: Rc::new(Term::Apply {
function: Rc::new(Term::Apply {
function: Rc::new(Term::Force(Rc::new(Term::Builtin(
DefaultFunction::IfThenElse,
)))),
argument: Rc::new(condition_term),
}),
//If this is just a var then don't include delay
argument: Rc::new(Term::Delay(Rc::new(branch_term))),
}),
//If this is just a var then don't include delay
argument: Rc::new(Term::Delay(Rc::new(final_if_term.clone()))),
};
}
Term::Force(Rc::new(final_if_term))
}
aiken_lang::expr::TypedExpr::RecordAccess {
location,
tipo,
label,
index,
record,
} => todo!(),
aiken_lang::expr::TypedExpr::ModuleSelect {
location,
tipo,
label,
module_name,
module_alias,
constructor,
} => todo!(),
aiken_lang::expr::TypedExpr::Todo {
location,
label,
tipo,
} => todo!(),
aiken_lang::expr::TypedExpr::RecordUpdate {
location,
tipo,
spread,
args,
} => todo!(),
aiken_lang::expr::TypedExpr::Negate { location, value } => todo!(),
};
terms
}
fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> { fn aiken_files(&mut self, dir: &Path, kind: ModuleKind) -> Result<(), Error> {
let paths = walkdir::WalkDir::new(dir) let paths = walkdir::WalkDir::new(dir)
.follow_links(true) .follow_links(true)

View File

@ -9,7 +9,7 @@ use interner::Interner;
use pallas_primitives::{alonzo::PlutusData, Fragment}; use pallas_primitives::{alonzo::PlutusData, Fragment};
use peg::{error::ParseError, str::LineCol}; use peg::{error::ParseError, str::LineCol};
mod interner; pub mod interner;
/// Parse a `Program` from a str. /// Parse a `Program` from a str.
pub fn program(src: &str) -> Result<Program<Name>, ParseError<LineCol>> { pub fn program(src: &str) -> Result<Program<Name>, ParseError<LineCol>> {

View File

@ -1,3 +1,11 @@
pub type ScriptContext { pub type ScriptContext {
thing: String, thing: String
}
pub type Datum {
something: String,
}
pub fn thing(a: Datum, b){
a.something == b
} }

View File

@ -1,10 +1,7 @@
use sample
use sample/mint use sample/mint
use sample/spend use sample/spend
pub type Datum {
something: String,
}
pub type Redeemer { pub type Redeemer {
Buy { id: Int } Buy { id: Int }
Sell(Int) Sell(Int)