Replaced binary tuple with struct
This commit is contained in:
parent
4fe388aca3
commit
b16a4eefe4
@ -1,39 +1,27 @@
|
||||
import "@typespec/openapi3";
|
||||
using TypeSpec.OpenAPI;
|
||||
import "@typespec/http";
|
||||
import "./models.tsp";
|
||||
using TypeSpec.Http;
|
||||
using Models;
|
||||
|
||||
enum BinaryOperator {
|
||||
AND,
|
||||
OR,
|
||||
IMPLICATION
|
||||
}
|
||||
|
||||
model ExpressionNot {
|
||||
not: Expression;
|
||||
}
|
||||
|
||||
// TODO tuple type, possible in OpenAPI 3.1, but unsupported in typespec
|
||||
model ExpressionBinary {
|
||||
operator: BinaryOperator;
|
||||
left: Expression;
|
||||
right: Expression;
|
||||
}
|
||||
|
||||
model ExpressionAtomic {
|
||||
atomic: string;
|
||||
}
|
||||
|
||||
@oneOf
|
||||
union Expression {
|
||||
ExpressionNot;
|
||||
ExpressionBinary;
|
||||
ExpressionAtomic;
|
||||
}
|
||||
|
||||
model SimplifyResponse {
|
||||
@service({
|
||||
title: "Simplify Truth Expressions",
|
||||
})
|
||||
namespace Simplify {
|
||||
model SimplifyResponse {
|
||||
before: string;
|
||||
after: string;
|
||||
orderOfOperations: string[];
|
||||
orderOfOperations?: string[] = [];
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
op simplify(): SimplifyResponse;
|
||||
model SimplifyOptions {
|
||||
lang: "en" | "nb" = "en";
|
||||
simplify: boolean = true;
|
||||
caseSensitive: boolean = false;
|
||||
}
|
||||
|
||||
op simplify(
|
||||
@path exp: string,
|
||||
@query query?: SimplifyOptions
|
||||
): SimplifyResponse;
|
||||
}
|
||||
|
31
spec/models.tsp
Normal file
31
spec/models.tsp
Normal file
@ -0,0 +1,31 @@
|
||||
import "@typespec/openapi3";
|
||||
using TypeSpec.OpenAPI;
|
||||
|
||||
namespace Models;
|
||||
|
||||
enum BinaryOperator {
|
||||
AND,
|
||||
OR,
|
||||
IMPLICATION
|
||||
}
|
||||
|
||||
model ExpressionNot {
|
||||
not: Expression;
|
||||
}
|
||||
|
||||
model ExpressionBinary {
|
||||
left: Expression;
|
||||
operator: BinaryOperator;
|
||||
right: Expression;
|
||||
}
|
||||
|
||||
model ExpressionAtomic {
|
||||
atomic: string;
|
||||
}
|
||||
|
||||
@oneOf
|
||||
union Expression {
|
||||
ExpressionNot;
|
||||
ExpressionBinary;
|
||||
ExpressionAtomic;
|
||||
}
|
@ -1,13 +1,23 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: (title)
|
||||
title: Simplify Truth Expressions
|
||||
version: 0.0.0
|
||||
tags: []
|
||||
paths:
|
||||
/:
|
||||
/{exp}:
|
||||
get:
|
||||
operationId: simplify
|
||||
parameters: []
|
||||
parameters:
|
||||
- name: exp
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: query
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
$ref: '#/components/schemas/SimplifyOptions'
|
||||
responses:
|
||||
'200':
|
||||
description: The request has succeeded.
|
||||
@ -17,50 +27,68 @@ paths:
|
||||
$ref: '#/components/schemas/SimplifyResponse'
|
||||
components:
|
||||
schemas:
|
||||
BinaryOperator:
|
||||
Expression:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/Models.ExpressionNot'
|
||||
- $ref: '#/components/schemas/Models.ExpressionBinary'
|
||||
- $ref: '#/components/schemas/Models.ExpressionAtomic'
|
||||
Models.BinaryOperator:
|
||||
type: string
|
||||
enum:
|
||||
- AND
|
||||
- OR
|
||||
- IMPLICATION
|
||||
Expression:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/ExpressionNot'
|
||||
- $ref: '#/components/schemas/ExpressionBinary'
|
||||
- $ref: '#/components/schemas/ExpressionAtomic'
|
||||
ExpressionAtomic:
|
||||
Models.ExpressionAtomic:
|
||||
type: object
|
||||
required:
|
||||
- atomic
|
||||
properties:
|
||||
atomic:
|
||||
type: string
|
||||
ExpressionBinary:
|
||||
Models.ExpressionBinary:
|
||||
type: object
|
||||
required:
|
||||
- operator
|
||||
- left
|
||||
- operator
|
||||
- right
|
||||
properties:
|
||||
operator:
|
||||
$ref: '#/components/schemas/BinaryOperator'
|
||||
left:
|
||||
$ref: '#/components/schemas/Expression'
|
||||
operator:
|
||||
$ref: '#/components/schemas/Models.BinaryOperator'
|
||||
right:
|
||||
$ref: '#/components/schemas/Expression'
|
||||
ExpressionNot:
|
||||
Models.ExpressionNot:
|
||||
type: object
|
||||
required:
|
||||
- not
|
||||
properties:
|
||||
not:
|
||||
$ref: '#/components/schemas/Expression'
|
||||
SimplifyOptions:
|
||||
type: object
|
||||
required:
|
||||
- lang
|
||||
- simplify
|
||||
- caseSensitive
|
||||
properties:
|
||||
lang:
|
||||
type: string
|
||||
enum:
|
||||
- en
|
||||
- nb
|
||||
default: en
|
||||
simplify:
|
||||
type: boolean
|
||||
default: true
|
||||
caseSensitive:
|
||||
type: boolean
|
||||
default: false
|
||||
SimplifyResponse:
|
||||
type: object
|
||||
required:
|
||||
- before
|
||||
- after
|
||||
- orderOfOperations
|
||||
- expression
|
||||
properties:
|
||||
before:
|
||||
@ -71,5 +99,6 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default: []
|
||||
expression:
|
||||
$ref: '#/components/schemas/Expression'
|
||||
|
@ -12,7 +12,7 @@ pub trait OppositeEq {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Expression {
|
||||
Not(Box<Expression>),
|
||||
Binary(Box<Expression>, BinaryOperator, Box<Expression>),
|
||||
Binary { left: Box<Expression>, operator: BinaryOperator, right: Box<Expression> },
|
||||
Atomic(String),
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ impl Expression {
|
||||
pub fn is_atomic(&self) -> bool {
|
||||
match self {
|
||||
Expression::Not(expr) => expr.is_atomic(),
|
||||
Expression::Binary(_, _, _) => false,
|
||||
Expression::Binary { .. } => false,
|
||||
Expression::Atomic(_) => true
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,7 @@ impl Expression {
|
||||
pub fn exists(&self, atomic_value: &str) -> bool {
|
||||
match self {
|
||||
Expression::Not(expr) => expr.exists(atomic_value),
|
||||
Expression::Binary(left, _, right) => left.exists(atomic_value) || right.exists(atomic_value),
|
||||
Expression::Binary { left, right, .. } => left.exists(atomic_value) || right.exists(atomic_value),
|
||||
Expression::Atomic(value) => value == atomic_value,
|
||||
}
|
||||
}
|
||||
@ -69,14 +69,14 @@ impl Display for Expression {
|
||||
match self {
|
||||
Expression::Not(expr) if expr.is_atomic() => write!(f, "¬{expr}"),
|
||||
Expression::Not(expr) => write!(f, "¬({expr})"),
|
||||
Expression::Binary(left, BinaryOperator::And, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::And, right } => {
|
||||
write!(f, "{left} ⋀ {right}")
|
||||
}
|
||||
// TODO do not use parentheses on root level or if several operators are on the same level
|
||||
Expression::Binary(left, BinaryOperator::Or, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Or, right } => {
|
||||
write!(f, "({left} ⋁ {right})")
|
||||
}
|
||||
Expression::Binary(left, BinaryOperator::Implication, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Implication, right } => {
|
||||
write!(f, "{left} ➔ {right}")
|
||||
}
|
||||
Expression::Atomic(value) => write!(f, "{value}"),
|
||||
|
@ -21,8 +21,8 @@ macro_rules! implies {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! binary {
|
||||
($left:expr, $op:expr, $right:expr) => {
|
||||
$crate::expressions::expression::Expression::Binary(Box::new($left), $op, Box::new($right))
|
||||
($left:expr, $operator:expr, $right:expr) => {
|
||||
$crate::expressions::expression::Expression::Binary { left: Box::new($left), operator: $operator, right: Box::new($right) }
|
||||
};
|
||||
}
|
||||
|
||||
@ -78,16 +78,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn eval_and() {
|
||||
assert_eq!(eval!("a" && "b"), Binary(Box::new(Atomic("a".to_string())), And, Box::new(Atomic("b".to_string()))));
|
||||
assert_eq!(eval!("a" && "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: And, right: Box::new(Atomic("b".to_string())) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_or() {
|
||||
assert_eq!(eval!("a" || "b"), Binary(Box::new(Atomic("a".to_string())), Or, Box::new(Atomic("b".to_string()))));
|
||||
assert_eq!(eval!("a" || "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: Or, right: Box::new(Atomic("b".to_string())) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_implies() {
|
||||
assert_eq!(eval!("a" => "b"), Binary(Box::new(Atomic("a".to_string())), Implication, Box::new(Atomic("b".to_string()))));
|
||||
assert_eq!(eval!("a" => "b"), Binary { left: Box::new(Atomic("a".to_string())), operator: Implication, right: Box::new(Atomic("b".to_string())) });
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ impl Simplify for Expression {
|
||||
fn elimination_of_implication(&self) -> Self {
|
||||
match self {
|
||||
Expression::Not(expr) => not!(expr.elimination_of_implication()),
|
||||
Expression::Binary(left, BinaryOperator::Implication, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Implication, right } => {
|
||||
let left = left.elimination_of_implication();
|
||||
let right = right.elimination_of_implication();
|
||||
or!(not!(left), right)
|
||||
}
|
||||
Expression::Binary(left, operator, right) => {
|
||||
Expression::Binary { left, operator, right } => {
|
||||
let left = left.elimination_of_implication();
|
||||
let right = right.elimination_of_implication();
|
||||
binary!(left, *operator, right)
|
||||
@ -54,7 +54,7 @@ impl Simplify for Expression {
|
||||
not!(expr.double_negation_elimination())
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, operator, right) => {
|
||||
Expression::Binary { left, operator, right } => {
|
||||
let left = left.double_negation_elimination();
|
||||
let right = right.double_negation_elimination();
|
||||
binary!(left, *operator, right)
|
||||
@ -67,13 +67,13 @@ impl Simplify for Expression {
|
||||
match self {
|
||||
Expression::Not(expr) => {
|
||||
match *expr.clone() {
|
||||
Expression::Binary(left, BinaryOperator::And, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::And, right } => {
|
||||
// TODO unnecessary cloning calls to de_morgans_laws?
|
||||
let left = not!(left.de_morgans_laws());
|
||||
let right = not!(right.de_morgans_laws());
|
||||
or!(left, right).de_morgans_laws()
|
||||
}
|
||||
Expression::Binary(left, BinaryOperator::Or, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Or, right } => {
|
||||
let left = not!(left.de_morgans_laws());
|
||||
let right = not!(right.de_morgans_laws());
|
||||
and!(left, right).de_morgans_laws()
|
||||
@ -81,7 +81,7 @@ impl Simplify for Expression {
|
||||
_ => not!(expr.de_morgans_laws()),
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, operator, right) => {
|
||||
Expression::Binary { left, operator, right } => {
|
||||
let left = left.de_morgans_laws();
|
||||
let right = right.de_morgans_laws();
|
||||
binary!(left, *operator, right)
|
||||
@ -93,10 +93,10 @@ impl Simplify for Expression {
|
||||
// TODO deduplicate code
|
||||
fn absorption_law(&self) -> Self {
|
||||
match self {
|
||||
Expression::Binary(left, BinaryOperator::And, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::And, right } => {
|
||||
let (left_ref, right_ref) = (left.as_ref(), right.as_ref());
|
||||
match (left_ref, right_ref) {
|
||||
(_, Expression::Binary(right_left, BinaryOperator::Or, right_right)) => {
|
||||
(_, Expression::Binary { left: right_left, operator: BinaryOperator::Or, right: right_right }) => {
|
||||
if left_ref == right_left.as_ref() || left_ref == right_right.as_ref() {
|
||||
return left.absorption_law();
|
||||
} else if right_left.is_atomic() && right_right.is_atomic() && left.opposite_eq(right_left) {
|
||||
@ -108,7 +108,7 @@ impl Simplify for Expression {
|
||||
}
|
||||
and!(left.absorption_law(), right.absorption_law())
|
||||
}
|
||||
(Expression::Binary(left_left, BinaryOperator::Or, left_right), _) => {
|
||||
(Expression::Binary { left: left_left, operator: BinaryOperator::Or, right: left_right }, _) => {
|
||||
if right_ref == left_left.as_ref() || right_ref == left_right.as_ref() {
|
||||
return right.absorption_law();
|
||||
} else if left_left.is_atomic() && left_right.is_atomic() && right.opposite_eq(left_left) {
|
||||
@ -123,10 +123,10 @@ impl Simplify for Expression {
|
||||
(left, right) => and!(left.absorption_law(), right.absorption_law())
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, BinaryOperator::Or, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Or, right } => {
|
||||
let (left_ref, right_ref) = (left.as_ref(), right.as_ref());
|
||||
match (left_ref, right_ref) {
|
||||
(_, Expression::Binary(right_left, BinaryOperator::And, right_right)) => {
|
||||
(_, Expression::Binary { left: right_left, operator: BinaryOperator::And, right: right_right }) => {
|
||||
if left_ref == right_left.as_ref() || left_ref == right_right.as_ref() {
|
||||
return left.absorption_law();
|
||||
} else if right_left.is_atomic() && right_right.is_atomic() && left.opposite_eq(right_left) {
|
||||
@ -138,7 +138,7 @@ impl Simplify for Expression {
|
||||
}
|
||||
or!(left.absorption_law(), right.absorption_law())
|
||||
}
|
||||
(Expression::Binary(left_left, BinaryOperator::And, left_right), _) => {
|
||||
(Expression::Binary { left: left_left, operator: BinaryOperator::And, right: left_right }, _) => {
|
||||
if right_ref == left_left.as_ref() || right_ref == left_right.as_ref() {
|
||||
return right.absorption_law();
|
||||
} else if left_left.is_atomic() && left_right.is_atomic() && right.opposite_eq(left_left) {
|
||||
@ -153,7 +153,7 @@ impl Simplify for Expression {
|
||||
(left, right) => or!(left.absorption_law(), right.absorption_law())
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, operator, right) => {
|
||||
Expression::Binary { left, operator, right } => {
|
||||
let left = left.absorption_law();
|
||||
let right = right.absorption_law();
|
||||
binary!(left, *operator, right)
|
||||
@ -170,14 +170,14 @@ impl Simplify for Expression {
|
||||
// TODO deduplicate code
|
||||
fn distribution_law(&self) -> Self {
|
||||
match self {
|
||||
Expression::Binary(left, BinaryOperator::And, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::And, right } => {
|
||||
match (left.as_ref(), right.as_ref()) {
|
||||
(Expression::Atomic(_), Expression::Binary(right_left, BinaryOperator::Or, right_right)) => {
|
||||
(Expression::Atomic(_), Expression::Binary { left: right_left, operator: BinaryOperator::Or, right: right_right }) => {
|
||||
let right_left = right_left.distribution_law();
|
||||
let right_right = right_right.distribution_law();
|
||||
or!(and!(*left.clone(), right_left), and!(*left.clone(), right_right))
|
||||
}
|
||||
(Expression::Binary(left_left, BinaryOperator::Or, left_right), Expression::Atomic(_)) => {
|
||||
(Expression::Binary { left: left_left, operator: BinaryOperator::Or, right: left_right }, Expression::Atomic(_)) => {
|
||||
let left_left = left_left.distribution_law();
|
||||
let left_right = left_right.distribution_law();
|
||||
or!(and!(left_left, *right.clone()), and!(left_right, *right.clone()))
|
||||
@ -185,14 +185,14 @@ impl Simplify for Expression {
|
||||
(left, right) => and!(left.distribution_law(), right.distribution_law())
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, BinaryOperator::Or, right) => {
|
||||
Expression::Binary { left, operator: BinaryOperator::Or, right } => {
|
||||
match (left.as_ref(), right.as_ref()) {
|
||||
(Expression::Atomic(_), Expression::Binary(right_left, BinaryOperator::And, right_right)) => {
|
||||
(Expression::Atomic(_), Expression::Binary { left: right_left, operator: BinaryOperator::And, right: right_right }) => {
|
||||
let right_left = right_left.distribution_law();
|
||||
let right_right = right_right.distribution_law();
|
||||
and!(or!(*left.clone(), right_left), or!(*left.clone(), right_right))
|
||||
}
|
||||
(Expression::Binary(left_left, BinaryOperator::And, left_right), Expression::Atomic(_)) => {
|
||||
(Expression::Binary { left: left_left, operator: BinaryOperator::And, right: left_right }, Expression::Atomic(_)) => {
|
||||
let left_left = left_left.distribution_law();
|
||||
let left_right = left_right.distribution_law();
|
||||
and!(or!(left_left, *right.clone()), or!(left_right, *right.clone()))
|
||||
@ -200,7 +200,7 @@ impl Simplify for Expression {
|
||||
(left, right) => or!(left.distribution_law(), right.distribution_law())
|
||||
}
|
||||
}
|
||||
Expression::Binary(left, operator, right) => {
|
||||
Expression::Binary { left, operator, right } => {
|
||||
let left = left.distribution_law();
|
||||
let right = right.distribution_law();
|
||||
binary!(left, *operator, right)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use tokio::net::{TcpListener, ToSocketAddrs};
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
use crate::routing::{simplify, table};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user