feat: support negation of int
* add unary op * parse, typecheck, and code gen it * express boolean not as unary op as well, previously called negate Co-authored-by: rvcas <x@rvcas.dev>
This commit is contained in:
parent
542e39f093
commit
083b7fcb5f
|
@ -3,7 +3,7 @@ use std::{collections::HashSet, sync::Arc};
|
|||
use uplc::builtins::DefaultFunction;
|
||||
|
||||
use crate::{
|
||||
ast::{AssignmentKind, BinOp, TypedRecordUpdateArg},
|
||||
ast::{AssignmentKind, BinOp, TypedRecordUpdateArg, UnOp},
|
||||
tipo::{Type, ValueConstructor},
|
||||
};
|
||||
|
||||
|
@ -229,8 +229,9 @@ pub enum Air {
|
|||
args: Vec<TypedRecordUpdateArg>,
|
||||
},
|
||||
|
||||
Negate {
|
||||
UnOp {
|
||||
scope: Vec<u64>,
|
||||
op: UnOp,
|
||||
},
|
||||
|
||||
TupleAccessor {
|
||||
|
@ -276,7 +277,7 @@ impl Air {
|
|||
| Air::ErrorTerm { scope, .. }
|
||||
| Air::Record { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
| Air::Negate { scope, .. }
|
||||
| Air::UnOp { scope, .. }
|
||||
| Air::Trace { scope, .. }
|
||||
| Air::TupleAccessor { scope, .. }
|
||||
| Air::TupleIndex { scope, .. }
|
||||
|
|
|
@ -613,6 +613,14 @@ pub enum BinOp {
|
|||
ModInt,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum UnOp {
|
||||
// !
|
||||
Not,
|
||||
// -
|
||||
Negate,
|
||||
}
|
||||
|
||||
impl BinOp {
|
||||
pub fn precedence(&self) -> u8 {
|
||||
// Ensure that this matches the other precedence function for guards
|
||||
|
|
|
@ -5,9 +5,10 @@ use vec1::Vec1;
|
|||
use crate::{
|
||||
ast::{
|
||||
Annotation, Arg, AssignmentKind, BinOp, CallArg, Clause, DefinitionLocation, IfBranch,
|
||||
Pattern, RecordUpdateSpread, Span, TodoKind, TypedRecordUpdateArg, UntypedRecordUpdateArg,
|
||||
Pattern, RecordUpdateSpread, Span, TodoKind, TypedRecordUpdateArg, UnOp,
|
||||
UntypedRecordUpdateArg,
|
||||
},
|
||||
builtins::{bool, void},
|
||||
builtins::void,
|
||||
tipo::{ModuleValueConstructor, PatternConstructor, Type, ValueConstructor},
|
||||
};
|
||||
|
||||
|
@ -161,16 +162,17 @@ pub enum TypedExpr {
|
|||
args: Vec<TypedRecordUpdateArg>,
|
||||
},
|
||||
|
||||
Negate {
|
||||
UnOp {
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
tipo: Arc<Type>,
|
||||
op: UnOp,
|
||||
},
|
||||
}
|
||||
|
||||
impl TypedExpr {
|
||||
pub fn tipo(&self) -> Arc<Type> {
|
||||
match self {
|
||||
Self::Negate { .. } => bool(),
|
||||
Self::Var { constructor, .. } => constructor.tipo.clone(),
|
||||
Self::Trace { then, .. } => then.tipo(),
|
||||
Self::Fn { tipo, .. }
|
||||
|
@ -181,6 +183,7 @@ impl TypedExpr {
|
|||
| Self::List { tipo, .. }
|
||||
| Self::Call { tipo, .. }
|
||||
| Self::If { tipo, .. }
|
||||
| Self::UnOp { tipo, .. }
|
||||
| Self::BinOp { tipo, .. }
|
||||
| Self::Tuple { tipo, .. }
|
||||
| Self::String { tipo, .. }
|
||||
|
@ -224,7 +227,7 @@ impl TypedExpr {
|
|||
| TypedExpr::ErrorTerm { .. }
|
||||
| TypedExpr::BinOp { .. }
|
||||
| TypedExpr::Tuple { .. }
|
||||
| TypedExpr::Negate { .. }
|
||||
| TypedExpr::UnOp { .. }
|
||||
| TypedExpr::String { .. }
|
||||
| TypedExpr::Sequence { .. }
|
||||
| TypedExpr::Pipeline { .. }
|
||||
|
@ -267,7 +270,7 @@ impl TypedExpr {
|
|||
| Self::BinOp { location, .. }
|
||||
| Self::Tuple { location, .. }
|
||||
| Self::String { location, .. }
|
||||
| Self::Negate { location, .. }
|
||||
| Self::UnOp { location, .. }
|
||||
| Self::Pipeline { location, .. }
|
||||
| Self::ByteArray { location, .. }
|
||||
| Self::Assignment { location, .. }
|
||||
|
@ -304,7 +307,7 @@ impl TypedExpr {
|
|||
| Self::BinOp { location, .. }
|
||||
| Self::Tuple { location, .. }
|
||||
| Self::String { location, .. }
|
||||
| Self::Negate { location, .. }
|
||||
| Self::UnOp { location, .. }
|
||||
| Self::Sequence { location, .. }
|
||||
| Self::Pipeline { location, .. }
|
||||
| Self::ByteArray { location, .. }
|
||||
|
@ -436,7 +439,8 @@ pub enum UntypedExpr {
|
|||
arguments: Vec<UntypedRecordUpdateArg>,
|
||||
},
|
||||
|
||||
Negate {
|
||||
UnOp {
|
||||
op: UnOp,
|
||||
location: Span,
|
||||
value: Box<Self>,
|
||||
},
|
||||
|
@ -511,7 +515,7 @@ impl UntypedExpr {
|
|||
| Self::TupleIndex { location, .. }
|
||||
| Self::FieldAccess { location, .. }
|
||||
| Self::RecordUpdate { location, .. }
|
||||
| Self::Negate { location, .. }
|
||||
| Self::UnOp { location, .. }
|
||||
| Self::If { location, .. } => *location,
|
||||
Self::Sequence {
|
||||
location,
|
||||
|
|
|
@ -695,7 +695,7 @@ impl<'comments> Formatter<'comments> {
|
|||
|
||||
UntypedExpr::Var { name, .. } => name.to_doc(),
|
||||
|
||||
UntypedExpr::Negate { value, .. } => self.negate(value),
|
||||
UntypedExpr::UnOp { value, .. } => self.negate(value),
|
||||
|
||||
UntypedExpr::Fn {
|
||||
is_capture: true,
|
||||
|
|
|
@ -7,7 +7,7 @@ pub mod lexer;
|
|||
pub mod token;
|
||||
|
||||
use crate::{
|
||||
ast::{self, BinOp, Span, TodoKind, UntypedDefinition, CAPTURE_VARIABLE},
|
||||
ast::{self, BinOp, Span, TodoKind, UnOp, UntypedDefinition, CAPTURE_VARIABLE},
|
||||
expr,
|
||||
};
|
||||
|
||||
|
@ -1221,14 +1221,17 @@ pub fn expr_parser(
|
|||
});
|
||||
|
||||
// Negate
|
||||
let op = just(Token::Bang);
|
||||
let op = choice((
|
||||
just(Token::Bang).to(UnOp::Not),
|
||||
just(Token::Minus).to(UnOp::Negate),
|
||||
));
|
||||
|
||||
let unary = op
|
||||
.ignored()
|
||||
.map_with_span(|_, span| span)
|
||||
.map_with_span(|op, span| (op, span))
|
||||
.repeated()
|
||||
.then(chained)
|
||||
.foldr(|span, value| expr::UntypedExpr::Negate {
|
||||
.foldr(|(un_op, span), value| expr::UntypedExpr::UnOp {
|
||||
op: un_op,
|
||||
location: span.union(value.location()),
|
||||
value: Box::new(value),
|
||||
})
|
||||
|
|
|
@ -9,13 +9,9 @@ use super::{error::ParseError, token::Token};
|
|||
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
|
||||
let int = choice((
|
||||
text::int(10),
|
||||
text::int(16),
|
||||
just("-")
|
||||
.ignore_then(text::int(10))
|
||||
.map(|value: String| format!("-{}", &value)),
|
||||
just("-")
|
||||
.ignore_then(text::int(16))
|
||||
.map(|value: String| format!("-{}", &value)),
|
||||
))
|
||||
.map(|value| Token::Int { value });
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, Arg, ArgName, AssignmentKind, BinOp, CallArg, Clause, ClauseGuard, Constant,
|
||||
RecordUpdateSpread, Span, TodoKind, TypedArg, TypedCallArg, TypedClause, TypedClauseGuard,
|
||||
TypedConstant, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg, UntypedArg,
|
||||
TypedConstant, TypedIfBranch, TypedMultiPattern, TypedRecordUpdateArg, UnOp, UntypedArg,
|
||||
UntypedClause, UntypedClauseGuard, UntypedConstant, UntypedIfBranch, UntypedMultiPattern,
|
||||
UntypedPattern, UntypedRecordUpdateArg,
|
||||
},
|
||||
|
@ -345,7 +345,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
arguments: args,
|
||||
} => self.infer_record_update(*constructor, spread, args, location),
|
||||
|
||||
UntypedExpr::Negate { location, value } => self.infer_negate(location, value),
|
||||
UntypedExpr::UnOp {
|
||||
location,
|
||||
value,
|
||||
op,
|
||||
} => self.infer_un_op(location, value, op),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,18 +538,26 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
})
|
||||
}
|
||||
|
||||
fn infer_negate(
|
||||
fn infer_un_op(
|
||||
&mut self,
|
||||
location: Span,
|
||||
value: Box<UntypedExpr>,
|
||||
op: UnOp,
|
||||
) -> Result<TypedExpr, Error> {
|
||||
let value = self.infer(*value)?;
|
||||
|
||||
self.unify(bool(), value.tipo(), value.location())?;
|
||||
let tipo = match op {
|
||||
UnOp::Not => bool(),
|
||||
UnOp::Negate => int(),
|
||||
};
|
||||
|
||||
Ok(TypedExpr::Negate {
|
||||
self.unify(tipo.clone(), value.tipo(), value.location())?;
|
||||
|
||||
Ok(TypedExpr::UnOp {
|
||||
location,
|
||||
value: Box::new(value),
|
||||
op,
|
||||
tipo,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::{
|
|||
air::Air,
|
||||
ast::{
|
||||
ArgName, AssignmentKind, BinOp, Clause, Pattern, Span, TypedArg, TypedDataType,
|
||||
TypedFunction,
|
||||
TypedFunction, UnOp,
|
||||
},
|
||||
builder::{
|
||||
check_when_pattern_needs, constants_ir, convert_constants_to_data, convert_data_to_type,
|
||||
|
@ -496,9 +496,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
});
|
||||
}
|
||||
TypedExpr::RecordUpdate { .. } => todo!(),
|
||||
TypedExpr::Negate { value, .. } => {
|
||||
ir_stack.push(Air::Negate {
|
||||
TypedExpr::UnOp { value, op, .. } => {
|
||||
ir_stack.push(Air::UnOp {
|
||||
scope: scope.clone(),
|
||||
op: *op,
|
||||
});
|
||||
|
||||
self.build_ir(value, ir_stack, scope);
|
||||
|
@ -3925,14 +3926,25 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
Air::Record { .. } => todo!(),
|
||||
Air::RecordUpdate { .. } => todo!(),
|
||||
Air::Negate { .. } => {
|
||||
Air::UnOp { op, .. } => {
|
||||
let value = arg_stack.pop().unwrap();
|
||||
|
||||
let term = if_else(
|
||||
value,
|
||||
Term::Constant(UplcConstant::Bool(false)),
|
||||
Term::Constant(UplcConstant::Bool(true)),
|
||||
);
|
||||
let term = match op {
|
||||
UnOp::Not => if_else(
|
||||
value,
|
||||
Term::Constant(UplcConstant::Bool(false)),
|
||||
Term::Constant(UplcConstant::Bool(true)),
|
||||
),
|
||||
UnOp::Negate => Term::Apply {
|
||||
function: Term::Apply {
|
||||
function: Term::Builtin(DefaultFunction::SubtractInteger).into(),
|
||||
argument: Term::Constant(UplcConstant::Integer(0)).into(),
|
||||
}
|
||||
.into(),
|
||||
argument: value.into(),
|
||||
},
|
||||
};
|
||||
|
||||
arg_stack.push(term);
|
||||
}
|
||||
Air::TupleIndex { .. } => todo!(),
|
||||
|
|
Loading…
Reference in New Issue