Merge pull request #390 from aiken-lang/acceptance-test-060--record-and-tuple-constants
Remove complex constants.
This commit is contained in:
commit
1aea586cab
|
@ -3,7 +3,7 @@ use std::{fmt, ops::Range, sync::Arc};
|
|||
use crate::{
|
||||
builtins::{self, bool},
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
tipo::{fields::FieldMap, PatternConstructor, Type, TypeInfo, ValueConstructor},
|
||||
tipo::{PatternConstructor, Type, TypeInfo},
|
||||
};
|
||||
|
||||
pub const ASSERT_VARIABLE: &str = "_try";
|
||||
|
@ -244,17 +244,17 @@ pub struct Use<PackageName> {
|
|||
pub unqualified: Vec<UnqualifiedImport>,
|
||||
}
|
||||
|
||||
pub type TypedModuleConstant = ModuleConstant<Arc<Type>, String>;
|
||||
pub type UntypedModuleConstant = ModuleConstant<(), ()>;
|
||||
pub type TypedModuleConstant = ModuleConstant<Arc<Type>>;
|
||||
pub type UntypedModuleConstant = ModuleConstant<()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ModuleConstant<T, ConstantRecordTag> {
|
||||
pub struct ModuleConstant<T> {
|
||||
pub doc: Option<String>,
|
||||
pub location: Span,
|
||||
pub public: bool,
|
||||
pub name: String,
|
||||
pub annotation: Option<Annotation>,
|
||||
pub value: Box<Constant<T, ConstantRecordTag>>,
|
||||
pub value: Box<Constant>,
|
||||
pub tipo: T,
|
||||
}
|
||||
|
||||
|
@ -270,11 +270,11 @@ pub struct Validator<T, Expr> {
|
|||
pub params: Vec<Arg<T>>,
|
||||
}
|
||||
|
||||
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String, String>;
|
||||
pub type UntypedDefinition = Definition<(), UntypedExpr, (), ()>;
|
||||
pub type TypedDefinition = Definition<Arc<Type>, TypedExpr, String>;
|
||||
pub type UntypedDefinition = Definition<(), UntypedExpr, ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
|
||||
pub enum Definition<T, Expr, PackageName> {
|
||||
Fn(Function<T, Expr>),
|
||||
|
||||
TypeAlias(TypeAlias<T>),
|
||||
|
@ -283,14 +283,14 @@ pub enum Definition<T, Expr, ConstantRecordTag, PackageName> {
|
|||
|
||||
Use(Use<PackageName>),
|
||||
|
||||
ModuleConstant(ModuleConstant<T, ConstantRecordTag>),
|
||||
ModuleConstant(ModuleConstant<T>),
|
||||
|
||||
Test(Function<T, Expr>),
|
||||
|
||||
Validator(Validator<T, Expr>),
|
||||
}
|
||||
|
||||
impl<A, B, C, E> Definition<A, B, C, E> {
|
||||
impl<A, B, C> Definition<A, B, C> {
|
||||
pub fn location(&self) -> Span {
|
||||
match self {
|
||||
Definition::Fn(Function { location, .. })
|
||||
|
@ -324,91 +324,31 @@ pub struct DefinitionLocation<'module> {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
pub type TypedConstant = Constant<Arc<Type>, String>;
|
||||
pub type UntypedConstant = Constant<(), ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Constant<T, RecordTag> {
|
||||
Int {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
pub enum Constant {
|
||||
Int { location: Span, value: String },
|
||||
|
||||
String {
|
||||
location: Span,
|
||||
value: String,
|
||||
},
|
||||
String { location: Span, value: String },
|
||||
|
||||
Tuple {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
},
|
||||
|
||||
List {
|
||||
location: Span,
|
||||
elements: Vec<Self>,
|
||||
tipo: T,
|
||||
},
|
||||
|
||||
Record {
|
||||
location: Span,
|
||||
module: Option<String>,
|
||||
name: String,
|
||||
args: Vec<CallArg<Self>>,
|
||||
tag: RecordTag,
|
||||
tipo: T,
|
||||
field_map: Option<FieldMap>,
|
||||
},
|
||||
|
||||
ByteArray {
|
||||
location: Span,
|
||||
bytes: Vec<u8>,
|
||||
},
|
||||
|
||||
Var {
|
||||
location: Span,
|
||||
module: Option<String>,
|
||||
name: String,
|
||||
constructor: Option<Box<ValueConstructor>>,
|
||||
tipo: T,
|
||||
},
|
||||
ByteArray { location: Span, bytes: Vec<u8> },
|
||||
}
|
||||
|
||||
impl TypedConstant {
|
||||
impl Constant {
|
||||
pub fn tipo(&self) -> Arc<Type> {
|
||||
match self {
|
||||
Constant::Int { .. } => builtins::int(),
|
||||
Constant::String { .. } => builtins::string(),
|
||||
Constant::ByteArray { .. } => builtins::byte_array(),
|
||||
Constant::Tuple { elements, .. } => {
|
||||
builtins::tuple(elements.iter().map(|e| e.tipo()).collect())
|
||||
}
|
||||
Constant::List { tipo, .. }
|
||||
| Constant::Record { tipo, .. }
|
||||
| Constant::Var { tipo, .. } => tipo.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Constant<A, B> {
|
||||
pub fn location(&self) -> Span {
|
||||
match self {
|
||||
Constant::Int { location, .. }
|
||||
| Constant::Tuple { location, .. }
|
||||
| Constant::List { location, .. }
|
||||
| Constant::String { location, .. }
|
||||
| Constant::Record { location, .. }
|
||||
| Constant::ByteArray { location, .. }
|
||||
| Constant::Var { location, .. } => *location,
|
||||
| Constant::ByteArray { location, .. } => *location,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_simple(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Int { .. } | Self::ByteArray { .. } | Self::String { .. }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub type TypedCallArg = CallArg<TypedExpr>;
|
||||
|
@ -836,15 +776,15 @@ pub type MultiPattern<PatternConstructor, Type> = Vec<Pattern<PatternConstructor
|
|||
pub type UntypedMultiPattern = MultiPattern<(), ()>;
|
||||
pub type TypedMultiPattern = MultiPattern<PatternConstructor, Arc<Type>>;
|
||||
|
||||
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>, String>;
|
||||
pub type UntypedClause = Clause<UntypedExpr, (), (), ()>;
|
||||
pub type TypedClause = Clause<TypedExpr, PatternConstructor, Arc<Type>>;
|
||||
pub type UntypedClause = Clause<UntypedExpr, (), ()>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Clause<Expr, PatternConstructor, Type, RecordTag> {
|
||||
pub struct Clause<Expr, PatternConstructor, Type> {
|
||||
pub location: Span,
|
||||
pub pattern: MultiPattern<PatternConstructor, Type>,
|
||||
pub alternative_patterns: Vec<MultiPattern<PatternConstructor, Type>>,
|
||||
pub guard: Option<ClauseGuard<Type, RecordTag>>,
|
||||
pub guard: Option<ClauseGuard<Type>>,
|
||||
pub then: Expr,
|
||||
}
|
||||
|
||||
|
@ -861,11 +801,11 @@ impl TypedClause {
|
|||
}
|
||||
}
|
||||
|
||||
pub type UntypedClauseGuard = ClauseGuard<(), ()>;
|
||||
pub type TypedClauseGuard = ClauseGuard<Arc<Type>, String>;
|
||||
pub type UntypedClauseGuard = ClauseGuard<()>;
|
||||
pub type TypedClauseGuard = ClauseGuard<Arc<Type>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ClauseGuard<Type, RecordTag> {
|
||||
pub enum ClauseGuard<Type> {
|
||||
Not {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
|
@ -925,10 +865,10 @@ pub enum ClauseGuard<Type, RecordTag> {
|
|||
name: String,
|
||||
},
|
||||
|
||||
Constant(Constant<Type, RecordTag>),
|
||||
Constant(Constant),
|
||||
}
|
||||
|
||||
impl<A, B> ClauseGuard<A, B> {
|
||||
impl<A> ClauseGuard<A> {
|
||||
pub fn location(&self) -> Span {
|
||||
match self {
|
||||
ClauseGuard::Constant(constant) => constant.location(),
|
||||
|
|
|
@ -397,8 +397,8 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
|
|||
}
|
||||
|
||||
pub fn rearrange_clauses(
|
||||
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>>,
|
||||
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>> {
|
||||
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>>,
|
||||
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>>> {
|
||||
let mut sorted_clauses = clauses;
|
||||
|
||||
// if we have a list sort clauses so we can plug holes for cases not covered by clauses
|
||||
|
@ -1066,11 +1066,7 @@ pub fn check_when_pattern_needs(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn constants_ir(
|
||||
literal: &Constant<Arc<Type>, String>,
|
||||
ir_stack: &mut Vec<Air>,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
pub fn constants_ir(literal: &Constant, ir_stack: &mut Vec<Air>, scope: Vec<u64>) {
|
||||
match literal {
|
||||
Constant::Int { value, .. } => {
|
||||
ir_stack.push(Air::Int {
|
||||
|
@ -1084,32 +1080,12 @@ pub fn constants_ir(
|
|||
value: value.clone(),
|
||||
});
|
||||
}
|
||||
Constant::Tuple { .. } => {
|
||||
todo!()
|
||||
}
|
||||
Constant::List { elements, tipo, .. } => {
|
||||
ir_stack.push(Air::List {
|
||||
scope: scope.clone(),
|
||||
count: elements.len(),
|
||||
tipo: tipo.clone(),
|
||||
tail: false,
|
||||
});
|
||||
|
||||
for element in elements {
|
||||
constants_ir(element, ir_stack, scope.clone());
|
||||
}
|
||||
}
|
||||
Constant::Record { .. } => {
|
||||
// ir_stack.push(Air::Record { scope, });
|
||||
todo!()
|
||||
}
|
||||
Constant::ByteArray { bytes, .. } => {
|
||||
ir_stack.push(Air::ByteArray {
|
||||
scope,
|
||||
bytes: bytes.clone(),
|
||||
});
|
||||
}
|
||||
Constant::Var { .. } => todo!(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2072,7 +2048,7 @@ pub fn replace_opaque_type(t: &mut Arc<Type>, data_types: IndexMap<DataTypeKey,
|
|||
}
|
||||
|
||||
pub fn handle_clause_guard(
|
||||
clause_guard: &ClauseGuard<Arc<Type>, String>,
|
||||
clause_guard: &ClauseGuard<Arc<Type>>,
|
||||
clause_guard_vec: &mut Vec<Air>,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
|
|
|
@ -103,7 +103,7 @@ pub enum TypedExpr {
|
|||
location: Span,
|
||||
tipo: Arc<Type>,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>, String>>,
|
||||
clauses: Vec<Clause<Self, PatternConstructor, Arc<Type>>>,
|
||||
},
|
||||
|
||||
If {
|
||||
|
@ -390,7 +390,7 @@ pub enum UntypedExpr {
|
|||
When {
|
||||
location: Span,
|
||||
subjects: Vec<Self>,
|
||||
clauses: Vec<Clause<Self, (), (), ()>>,
|
||||
clauses: Vec<Clause<Self, (), ()>>,
|
||||
},
|
||||
|
||||
If {
|
||||
|
|
|
@ -7,10 +7,10 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, ClauseGuard, Constant, DataType,
|
||||
Definition, Function, IfBranch, ModuleConstant, Pattern, RecordConstructor,
|
||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg,
|
||||
TypedConstant, UnOp, UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard,
|
||||
UntypedDefinition, UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg,
|
||||
Use, Validator, CAPTURE_VARIABLE,
|
||||
RecordConstructorArg, RecordUpdateSpread, Span, TraceKind, TypeAlias, TypedArg, UnOp,
|
||||
UnqualifiedImport, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedDefinition,
|
||||
UntypedFunction, UntypedModule, UntypedPattern, UntypedRecordUpdateArg, Use, Validator,
|
||||
CAPTURE_VARIABLE,
|
||||
},
|
||||
docvec,
|
||||
expr::{UntypedExpr, DEFAULT_ERROR_STR, DEFAULT_TODO_STR},
|
||||
|
@ -324,82 +324,15 @@ impl<'comments> Formatter<'comments> {
|
|||
})
|
||||
}
|
||||
|
||||
fn const_expr<'a, A, B>(&mut self, value: &'a Constant<A, B>) -> Document<'a> {
|
||||
fn const_expr<'a>(&mut self, value: &'a Constant) -> Document<'a> {
|
||||
match value {
|
||||
Constant::ByteArray { bytes, .. } => self.bytearray(bytes),
|
||||
Constant::Int { value, .. } => value.to_doc(),
|
||||
|
||||
Constant::String { value, .. } => self.string(value),
|
||||
|
||||
Constant::List { elements, .. } => {
|
||||
let comma: fn() -> Document<'a> = if elements.iter().all(Constant::is_simple) {
|
||||
|| flex_break(",", ", ")
|
||||
} else {
|
||||
|| break_(",", ", ")
|
||||
};
|
||||
let elements_document = join(elements.iter().map(|e| self.const_expr(e)), comma());
|
||||
list(elements_document, elements.len(), None)
|
||||
}
|
||||
|
||||
Constant::Record {
|
||||
name,
|
||||
args,
|
||||
module: None,
|
||||
..
|
||||
} if args.is_empty() => name.to_doc(),
|
||||
|
||||
Constant::Record {
|
||||
name,
|
||||
args,
|
||||
module: Some(m),
|
||||
..
|
||||
} if args.is_empty() => m.to_doc().append(".").append(name.as_str()),
|
||||
|
||||
Constant::Record {
|
||||
name,
|
||||
args,
|
||||
module: None,
|
||||
..
|
||||
} => name
|
||||
.to_doc()
|
||||
.append(wrap_args(
|
||||
args.iter()
|
||||
.map(|a| (self.constant_call_arg(a), a.label.is_some())),
|
||||
))
|
||||
.group(),
|
||||
|
||||
Constant::Record {
|
||||
name,
|
||||
args,
|
||||
module: Some(m),
|
||||
..
|
||||
} => m
|
||||
.to_doc()
|
||||
.append(".")
|
||||
.append(name.as_str())
|
||||
.append(wrap_args(
|
||||
args.iter()
|
||||
.map(|a| (self.constant_call_arg(a), a.label.is_some())),
|
||||
))
|
||||
.group(),
|
||||
|
||||
Constant::Var {
|
||||
name, module: None, ..
|
||||
} => name.to_doc(),
|
||||
|
||||
Constant::Var {
|
||||
name,
|
||||
module: Some(module),
|
||||
..
|
||||
} => docvec![module, ".", name],
|
||||
|
||||
Constant::Tuple { elements, .. } => {
|
||||
wrap_args(elements.iter().map(|e| (self.const_expr(e), false))).group()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a TypedConstant) -> Document<'a> {
|
||||
pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a Constant) -> Document<'a> {
|
||||
let mut printer = tipo::pretty::Printer::new();
|
||||
name.to_doc()
|
||||
.append(": ")
|
||||
|
@ -1631,13 +1564,6 @@ impl<'comments> Formatter<'comments> {
|
|||
}
|
||||
}
|
||||
|
||||
fn constant_call_arg<'a, A, B>(&mut self, arg: &'a CallArg<Constant<A, B>>) -> Document<'a> {
|
||||
match &arg.label {
|
||||
None => self.const_expr(&arg.value),
|
||||
Some(s) => s.to_doc().append(": ").append(self.const_expr(&arg.value)),
|
||||
}
|
||||
}
|
||||
|
||||
fn un_op<'a>(&mut self, value: &'a UntypedExpr, op: &'a UnOp) -> Document<'a> {
|
||||
match op {
|
||||
UnOp::Not => docvec!["!", self.wrap_unary_op(value)],
|
||||
|
|
|
@ -386,162 +386,32 @@ fn constant_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
|
|||
})
|
||||
}
|
||||
|
||||
fn constant_value_parser() -> impl Parser<Token, ast::UntypedConstant, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
fn constant_value_parser() -> impl Parser<Token, ast::Constant, Error = ParseError> {
|
||||
let constant_string_parser =
|
||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||
ast::UntypedConstant::String {
|
||||
ast::Constant::String {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
});
|
||||
|
||||
let constant_int_parser =
|
||||
select! {Token::Int {value} => value}.map_with_span(|value, span| {
|
||||
ast::UntypedConstant::Int {
|
||||
select! {Token::Int {value} => value}.map_with_span(|value, span| ast::Constant::Int {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
});
|
||||
|
||||
let constant_tuple_parser = r
|
||||
.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.at_least(2)
|
||||
.allow_trailing()
|
||||
.delimited_by(
|
||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||
just(Token::RightParen),
|
||||
)
|
||||
.map_with_span(|elements, span| ast::UntypedConstant::Tuple {
|
||||
location: span,
|
||||
elements,
|
||||
});
|
||||
|
||||
let constant_bytearray_parser =
|
||||
bytearray_parser().map_with_span(|bytes, span| ast::UntypedConstant::ByteArray {
|
||||
bytearray_parser().map_with_span(|bytes, span| ast::Constant::ByteArray {
|
||||
location: span,
|
||||
bytes,
|
||||
});
|
||||
|
||||
let constant_list_parser = r
|
||||
.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare))
|
||||
.map_with_span(|elements, span| ast::UntypedConstant::List {
|
||||
location: span,
|
||||
elements,
|
||||
tipo: (),
|
||||
});
|
||||
|
||||
let constant_record_parser = choice((
|
||||
choice((
|
||||
select! {Token::Name { name } => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then(select! {Token::UpName { name } => name})
|
||||
.then(
|
||||
select! {Token::Name {name} => name}
|
||||
.then_ignore(just(Token::Colon))
|
||||
.or_not()
|
||||
.then(r.clone())
|
||||
.validate(|(label_opt, value), span, emit| {
|
||||
let label = if label_opt.is_some() {
|
||||
label_opt
|
||||
} else if let ast::UntypedConstant::Var { name, .. } = &value {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
emit(ParseError::expected_input_found(
|
||||
value.location(),
|
||||
None,
|
||||
Some(error::Pattern::RecordPunning),
|
||||
));
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
ast::CallArg {
|
||||
location: span,
|
||||
value,
|
||||
label,
|
||||
}
|
||||
})
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(
|
||||
|((module, name), args), span| ast::UntypedConstant::Record {
|
||||
location: span,
|
||||
module,
|
||||
name,
|
||||
args,
|
||||
tag: (),
|
||||
tipo: (),
|
||||
field_map: None,
|
||||
},
|
||||
),
|
||||
select! {Token::Name { name } => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then(select! {Token::UpName { name } => name})
|
||||
.then(
|
||||
r.clone()
|
||||
.map_with_span(|value, span| ast::CallArg {
|
||||
location: span,
|
||||
value,
|
||||
label: None,
|
||||
})
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
)
|
||||
.map_with_span(
|
||||
|((module, name), args), span| ast::UntypedConstant::Record {
|
||||
location: span,
|
||||
module,
|
||||
name,
|
||||
args,
|
||||
tag: (),
|
||||
tipo: (),
|
||||
field_map: None,
|
||||
},
|
||||
),
|
||||
)),
|
||||
select! {Token::Name { name } => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.then(select! {Token::Name{name} => name})
|
||||
.map_with_span(|(module, name), span: Span| ast::UntypedConstant::Var {
|
||||
location: span.union(span),
|
||||
module: Some(module),
|
||||
name,
|
||||
constructor: None,
|
||||
tipo: (),
|
||||
}),
|
||||
));
|
||||
|
||||
let constant_var_parser =
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||
ast::UntypedConstant::Var {
|
||||
location: span,
|
||||
module: None,
|
||||
name,
|
||||
constructor: None,
|
||||
tipo: (),
|
||||
}
|
||||
});
|
||||
|
||||
choice((
|
||||
constant_string_parser,
|
||||
constant_int_parser,
|
||||
constant_bytearray_parser,
|
||||
constant_tuple_parser,
|
||||
constant_list_parser,
|
||||
constant_record_parser,
|
||||
constant_var_parser,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn bytearray_parser() -> impl Parser<Token, Vec<u8>, Error = ParseError> {
|
||||
|
@ -1407,8 +1277,7 @@ pub fn expr_parser(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<(), ()>, Error = ParseError>
|
||||
{
|
||||
pub fn when_clause_guard_parser() -> impl Parser<Token, ast::ClauseGuard<()>, Error = ParseError> {
|
||||
recursive(|r| {
|
||||
let var_parser = select! {
|
||||
Token::Name { name } => name,
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{cell::RefCell, collections::HashMap, ops::Deref, sync::Arc};
|
|||
use uplc::{ast::Type as UplcType, builtins::DefaultFunction};
|
||||
|
||||
use crate::{
|
||||
ast::{Constant, DefinitionLocation, ModuleKind, Span, TypedConstant},
|
||||
ast::{Constant, DefinitionLocation, ModuleKind, Span},
|
||||
tipo::fields::FieldMap,
|
||||
};
|
||||
|
||||
|
@ -584,7 +584,7 @@ pub enum ValueConstructorVariant {
|
|||
ModuleConstant {
|
||||
location: Span,
|
||||
module: String,
|
||||
literal: Constant<Arc<Type>, String>,
|
||||
literal: Constant,
|
||||
},
|
||||
|
||||
/// A function belonging to the module
|
||||
|
@ -744,7 +744,7 @@ pub enum ModuleValueConstructor {
|
|||
},
|
||||
|
||||
Constant {
|
||||
literal: TypedConstant,
|
||||
literal: Constant,
|
||||
location: Span,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant,
|
||||
IfBranch, RecordUpdateSpread, Span, TraceKind, Tracing, TypedArg, TypedCallArg,
|
||||
TypedClause, TypedClauseGuard, TypedConstant, TypedIfBranch, TypedMultiPattern,
|
||||
TypedRecordUpdateArg, UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedConstant,
|
||||
UntypedIfBranch, UntypedMultiPattern, UntypedPattern, UntypedRecordUpdateArg,
|
||||
TypedClause, TypedClauseGuard, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg,
|
||||
UnOp, UntypedArg, UntypedClause, UntypedClauseGuard, UntypedIfBranch, UntypedMultiPattern,
|
||||
UntypedPattern, UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{bool, byte_array, function, int, list, string, tuple},
|
||||
expr::{TypedExpr, UntypedExpr},
|
||||
|
@ -22,8 +22,7 @@ use super::{
|
|||
hydrator::Hydrator,
|
||||
pattern::PatternTyper,
|
||||
pipe::PipeTyper,
|
||||
ModuleValueConstructor, PatternConstructor, RecordAccessor, Type, ValueConstructor,
|
||||
ValueConstructorVariant,
|
||||
PatternConstructor, RecordAccessor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -48,7 +47,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
&mut self,
|
||||
subjects_count: usize,
|
||||
subjects: &[Arc<Type>],
|
||||
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>],
|
||||
typed_clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
|
||||
location: Span,
|
||||
) -> Result<(), Vec<String>> {
|
||||
// Because exhaustiveness checking in presence of multiple subjects is similar
|
||||
|
@ -1338,29 +1337,13 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok((typed_pattern, typed_alternatives))
|
||||
}
|
||||
|
||||
fn infer_const_tuple(
|
||||
&mut self,
|
||||
untyped_elements: Vec<UntypedConstant>,
|
||||
location: Span,
|
||||
) -> Result<TypedConstant, Error> {
|
||||
let mut elements = Vec::with_capacity(untyped_elements.len());
|
||||
|
||||
for element in untyped_elements {
|
||||
let element = self.infer_const(&None, element)?;
|
||||
|
||||
elements.push(element);
|
||||
}
|
||||
|
||||
Ok(Constant::Tuple { elements, location })
|
||||
}
|
||||
|
||||
// TODO: extract the type annotation checking into a infer_module_const
|
||||
// function that uses this function internally
|
||||
pub fn infer_const(
|
||||
&mut self,
|
||||
annotation: &Option<Annotation>,
|
||||
value: UntypedConstant,
|
||||
) -> Result<TypedConstant, Error> {
|
||||
value: Constant,
|
||||
) -> Result<Constant, Error> {
|
||||
let inferred = match value {
|
||||
Constant::Int {
|
||||
location, value, ..
|
||||
|
@ -1370,216 +1353,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
location, value, ..
|
||||
} => Ok(Constant::String { location, value }),
|
||||
|
||||
Constant::Tuple {
|
||||
elements, location, ..
|
||||
} => self.infer_const_tuple(elements, location),
|
||||
|
||||
Constant::List {
|
||||
elements, location, ..
|
||||
} => self.infer_const_list(elements, location),
|
||||
|
||||
Constant::ByteArray { location, bytes } => Ok(Constant::ByteArray { location, bytes }),
|
||||
|
||||
Constant::Record {
|
||||
module,
|
||||
location,
|
||||
name,
|
||||
args,
|
||||
// field_map, is always None here because untyped not yet unified
|
||||
..
|
||||
} if args.is_empty() => {
|
||||
// Register the module as having been used if it was imported
|
||||
if let Some(ref module) = &module {
|
||||
self.environment.unused_modules.remove(module);
|
||||
}
|
||||
|
||||
// Type check the record constructor
|
||||
let constructor = self.infer_value_constructor(&module, &name, &location)?;
|
||||
|
||||
let (tag, field_map) = match &constructor.variant {
|
||||
ValueConstructorVariant::Record {
|
||||
name, field_map, ..
|
||||
} => (name.clone(), field_map.clone()),
|
||||
|
||||
ValueConstructorVariant::ModuleFn { .. }
|
||||
| ValueConstructorVariant::LocalVariable { .. } => {
|
||||
return Err(Error::NonLocalClauseGuardVariable { location, name })
|
||||
}
|
||||
|
||||
// TODO: remove this clone. Could use an rc instead
|
||||
ValueConstructorVariant::ModuleConstant { literal, .. } => {
|
||||
return Ok(literal.clone())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Constant::Record {
|
||||
module,
|
||||
location,
|
||||
name,
|
||||
args: vec![],
|
||||
tipo: constructor.tipo,
|
||||
tag,
|
||||
field_map,
|
||||
})
|
||||
}
|
||||
|
||||
Constant::Record {
|
||||
module,
|
||||
location,
|
||||
name,
|
||||
mut args,
|
||||
// field_map, is always None here because untyped not yet unified
|
||||
..
|
||||
} => {
|
||||
// Register the module as having been used if it was imported
|
||||
if let Some(ref module) = &module {
|
||||
self.environment.unused_modules.remove(module);
|
||||
}
|
||||
|
||||
let constructor = self.infer_value_constructor(&module, &name, &location)?;
|
||||
|
||||
let (tag, field_map) = match &constructor.variant {
|
||||
ValueConstructorVariant::Record {
|
||||
name, field_map, ..
|
||||
} => (name.clone(), field_map.clone()),
|
||||
|
||||
ValueConstructorVariant::ModuleFn { .. }
|
||||
| ValueConstructorVariant::LocalVariable { .. } => {
|
||||
return Err(Error::NonLocalClauseGuardVariable { location, name })
|
||||
}
|
||||
|
||||
// TODO: remove this clone. Could be an rc instead
|
||||
ValueConstructorVariant::ModuleConstant { literal, .. } => {
|
||||
return Ok(literal.clone())
|
||||
}
|
||||
};
|
||||
|
||||
// Pretty much all the other infer functions operate on UntypedExpr
|
||||
// or TypedExpr rather than ClauseGuard. To make things easier we
|
||||
// build the TypedExpr equivalent of the constructor and use that
|
||||
// TODO: resvisit this. It is rather awkward at present how we
|
||||
// have to convert to this other data structure.
|
||||
let fun = match &module {
|
||||
Some(module_name) => {
|
||||
let tipo = Arc::clone(&constructor.tipo);
|
||||
|
||||
let module_name = self
|
||||
.environment
|
||||
.imported_modules
|
||||
.get(module_name)
|
||||
.expect("Failed to find previously located module import")
|
||||
.1
|
||||
.name
|
||||
.clone();
|
||||
|
||||
let module_value_constructor = ModuleValueConstructor::Record {
|
||||
name: name.clone(),
|
||||
field_map: field_map.clone(),
|
||||
arity: args.len(),
|
||||
tipo: Arc::clone(&tipo),
|
||||
location: constructor.variant.location(),
|
||||
};
|
||||
|
||||
TypedExpr::ModuleSelect {
|
||||
label: name.clone(),
|
||||
module_alias: module_name.clone(),
|
||||
module_name,
|
||||
tipo,
|
||||
constructor: module_value_constructor,
|
||||
location,
|
||||
}
|
||||
}
|
||||
|
||||
None => TypedExpr::Var {
|
||||
constructor,
|
||||
location,
|
||||
name: name.clone(),
|
||||
},
|
||||
};
|
||||
|
||||
// This is basically the same code as do_infer_call_with_known_fun()
|
||||
// except the args are typed with infer_clause_guard() here.
|
||||
// This duplication is a bit awkward but it works!
|
||||
// Potentially this could be improved later
|
||||
match self.get_field_map(&fun, location)? {
|
||||
// The fun has a field map so labelled arguments may be present and need to be reordered.
|
||||
Some(field_map) => field_map.reorder(&mut args, location)?,
|
||||
|
||||
// The fun has no field map and so we error if arguments have been labelled
|
||||
None => assert_no_labeled_arguments(&args)
|
||||
.map(|(location, label)| {
|
||||
Err(Error::UnexpectedLabeledArg { location, label })
|
||||
})
|
||||
.unwrap_or(Ok(()))?,
|
||||
}
|
||||
|
||||
let (mut args_types, return_type) = self.environment.match_fun_type(
|
||||
fun.tipo(),
|
||||
args.len(),
|
||||
fun.location(),
|
||||
location,
|
||||
)?;
|
||||
|
||||
let mut typed_args = Vec::new();
|
||||
|
||||
for (tipo, arg) in args_types.iter_mut().zip(args) {
|
||||
let CallArg {
|
||||
label,
|
||||
value,
|
||||
location,
|
||||
} = arg;
|
||||
|
||||
let value = self.infer_const(&None, value)?;
|
||||
|
||||
self.unify(tipo.clone(), value.tipo(), value.location(), tipo.is_data())?;
|
||||
|
||||
typed_args.push(CallArg {
|
||||
label,
|
||||
value,
|
||||
location,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Constant::Record {
|
||||
module,
|
||||
location,
|
||||
name,
|
||||
args: typed_args,
|
||||
tipo: return_type,
|
||||
tag,
|
||||
field_map,
|
||||
})
|
||||
}
|
||||
Constant::Var {
|
||||
location,
|
||||
module,
|
||||
name,
|
||||
..
|
||||
} => {
|
||||
// Register the module as having been used if it was imported
|
||||
if let Some(ref module) = &module {
|
||||
self.environment.unused_modules.remove(module);
|
||||
}
|
||||
|
||||
// Infer the type of this constant
|
||||
let constructor = self.infer_value_constructor(&module, &name, &location)?;
|
||||
|
||||
match constructor.variant {
|
||||
ValueConstructorVariant::ModuleConstant { .. }
|
||||
| ValueConstructorVariant::ModuleFn { .. } => Ok(Constant::Var {
|
||||
location,
|
||||
module,
|
||||
name,
|
||||
tipo: Arc::clone(&constructor.tipo),
|
||||
constructor: Some(Box::from(constructor)),
|
||||
}),
|
||||
// constructor.variant cannot be a LocalVariable because module constants can
|
||||
// only be defined at module scope. It also cannot be a Record because then
|
||||
// this constant would have been parsed as a Constant::Record. Therefore this
|
||||
// code is unreachable.
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}?;
|
||||
|
||||
// Check type annotation is accurate.
|
||||
|
@ -1597,30 +1371,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(inferred)
|
||||
}
|
||||
|
||||
fn infer_const_list(
|
||||
&mut self,
|
||||
untyped_elements: Vec<UntypedConstant>,
|
||||
location: Span,
|
||||
) -> Result<TypedConstant, Error> {
|
||||
let tipo = self.new_unbound_var();
|
||||
|
||||
let mut elements = Vec::with_capacity(untyped_elements.len());
|
||||
|
||||
for element in untyped_elements {
|
||||
let element = self.infer_const(&None, element)?;
|
||||
|
||||
self.unify(tipo.clone(), element.tipo(), element.location(), false)?;
|
||||
|
||||
elements.push(element);
|
||||
}
|
||||
|
||||
Ok(Constant::List {
|
||||
elements,
|
||||
location,
|
||||
tipo: list(tipo),
|
||||
})
|
||||
}
|
||||
|
||||
fn infer_if(
|
||||
&mut self,
|
||||
branches: Vec1<UntypedIfBranch>,
|
||||
|
|
|
@ -689,7 +689,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
&mut self,
|
||||
ir_stack: &mut Vec<Air>,
|
||||
clause_properties: &mut ClauseProperties,
|
||||
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>, String>],
|
||||
clauses: &[Clause<TypedExpr, PatternConstructor, Arc<Type>>],
|
||||
subject_type: &Arc<Type>,
|
||||
scope: Vec<u64>,
|
||||
) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# This file was generated by Aiken
|
||||
# You typically do not need to edit this file
|
||||
|
||||
requirements = []
|
||||
packages = []
|
|
@ -0,0 +1,2 @@
|
|||
name = "aiken-lang/acceptance_test_060"
|
||||
version = "0.0.0"
|
|
@ -0,0 +1,17 @@
|
|||
const int_constant = 42
|
||||
|
||||
test int() {
|
||||
int_constant == 42
|
||||
}
|
||||
|
||||
const bytearray_constant = #"abcd"
|
||||
|
||||
test bytearray() {
|
||||
bytearray_constant == #"abcd"
|
||||
}
|
||||
|
||||
const string_constant = "FOO"
|
||||
|
||||
test string() {
|
||||
string_constant == "FOO"
|
||||
}
|
Loading…
Reference in New Issue