diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts index a3f50f16e..0c4bdccd7 100644 --- a/src/api/js/src/high-level/high-level.ts +++ b/src/api/js/src/high-level/high-level.ts @@ -96,6 +96,9 @@ import { RatNum, RCFNum, RCFNumCreation, + Re, + ReSort, + ReCreation, Seq, SeqSort, Simplifier, @@ -297,6 +300,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new FPRMSortImpl(ast); case Z3_sort_kind.Z3_SEQ_SORT: return new SeqSortImpl(ast); + case Z3_sort_kind.Z3_RE_SORT: + return new ReSortImpl(ast); case Z3_sort_kind.Z3_ARRAY_SORT: return new ArraySortImpl(ast); default: @@ -340,6 +345,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new FPRMImpl(ast); case Z3_sort_kind.Z3_SEQ_SORT: return new SeqImpl(ast); + case Z3_sort_kind.Z3_RE_SORT: + return new ReImpl(ast); case Z3_sort_kind.Z3_ARRAY_SORT: return new ArrayImpl(ast); default: @@ -611,6 +618,18 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return r; } + function isReSort(obj: unknown): obj is ReSort { + const r = obj instanceof ReSortImpl; + r && _assertContext(obj); + return r; + } + + function isRe(obj: unknown): obj is Re { + const r = obj instanceof ReImpl; + r && _assertContext(obj); + return r; + } + function isStringSort(obj: unknown): obj is SeqSort { return isSeqSort(obj) && obj.isString(); } @@ -1000,6 +1019,17 @@ export function createApi(Z3: Z3Core): Z3HighLevel { }, }; + const Re = { + sort>(seqSort: SeqSortRef): ReSort { + return new ReSortImpl(Z3.mk_re_sort(contextPtr, seqSort.ptr)); + }, + + toRe(seq: Seq | string): Re { + const seqExpr = isSeq(seq) ? seq : String.val(seq); + return new ReImpl(check(Z3.mk_seq_to_re(contextPtr, seqExpr.ast))); + }, + }; + const Array = { sort, RangeSort extends AnySort>( ...sig: [...DomainSort, RangeSort] @@ -1765,6 +1795,91 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new BoolImpl(check(Z3.mk_set_subset(contextPtr, a.ast, b.ast))); } + ////////////////////// + // Regular Expressions + ////////////////////// + + function InRe(seq: Seq | string, re: Re): Bool { + const seqExpr = isSeq(seq) ? seq : String.val(seq); + return new BoolImpl(check(Z3.mk_seq_in_re(contextPtr, seqExpr.ast, re.ast))); + } + + function Union>(...res: Re[]): Re { + if (res.length === 0) { + throw new Error('Union requires at least one argument'); + } + if (res.length === 1) { + return res[0]; + } + return new ReImpl(check(Z3.mk_re_union(contextPtr, res.map(r => r.ast)))); + } + + function Intersect>(...res: Re[]): Re { + if (res.length === 0) { + throw new Error('Intersect requires at least one argument'); + } + if (res.length === 1) { + return res[0]; + } + return new ReImpl(check(Z3.mk_re_intersect(contextPtr, res.map(r => r.ast)))); + } + + function ReConcat>(...res: Re[]): Re { + if (res.length === 0) { + throw new Error('ReConcat requires at least one argument'); + } + if (res.length === 1) { + return res[0]; + } + return new ReImpl(check(Z3.mk_re_concat(contextPtr, res.map(r => r.ast)))); + } + + function Plus>(re: Re): Re { + return new ReImpl(check(Z3.mk_re_plus(contextPtr, re.ast))); + } + + function Star>(re: Re): Re { + return new ReImpl(check(Z3.mk_re_star(contextPtr, re.ast))); + } + + function Option>(re: Re): Re { + return new ReImpl(check(Z3.mk_re_option(contextPtr, re.ast))); + } + + function Complement>(re: Re): Re { + return new ReImpl(check(Z3.mk_re_complement(contextPtr, re.ast))); + } + + function Diff>(a: Re, b: Re): Re { + return new ReImpl(check(Z3.mk_re_diff(contextPtr, a.ast, b.ast))); + } + + function Range>(lo: Seq | string, hi: Seq | string): Re { + const loSeq = isSeq(lo) ? lo : String.val(lo); + const hiSeq = isSeq(hi) ? hi : String.val(hi); + return new ReImpl(check(Z3.mk_re_range(contextPtr, loSeq.ast, hiSeq.ast))); + } + + function Loop>(re: Re, lo: number, hi: number = 0): Re { + return new ReImpl(check(Z3.mk_re_loop(contextPtr, re.ast, lo, hi))); + } + + function Power>(re: Re, n: number): Re { + return new ReImpl(check(Z3.mk_re_power(contextPtr, re.ast, n))); + } + + function AllChar>(reSort: ReSort): Re { + return new ReImpl(check(Z3.mk_re_allchar(contextPtr, reSort.ptr))); + } + + function Empty>(reSort: ReSort): Re { + return new ReImpl(check(Z3.mk_re_empty(contextPtr, reSort.ptr))); + } + + function Full>(reSort: ReSort): Re { + return new ReImpl(check(Z3.mk_re_full(contextPtr, reSort.ptr))); + } + function mkPartialOrder(sort: Sort, index: number): FuncDecl { return new FuncDeclImpl(check(Z3.mk_partial_order(contextPtr, sort.ptr, index))); } @@ -4024,6 +4139,71 @@ export function createApi(Z3: Z3Core): Z3HighLevel { } } + class ReSortImpl = SeqSort> extends SortImpl implements ReSort { + declare readonly __typename: ReSort['__typename']; + + basis(): SeqSortRef { + return _toSort(check(Z3.get_re_sort_basis(contextPtr, this.ptr))) as SeqSortRef; + } + + cast(other: Re): Re; + cast(other: CoercibleToExpr): Expr; + cast(other: any): any { + if (isRe(other)) { + _assertContext(other); + return other; + } + throw new Error("Can't cast to ReSort"); + } + } + + class ReImpl = SeqSort> + extends ExprImpl> + implements Re + { + declare readonly __typename: Re['__typename']; + + plus(): Re { + return new ReImpl(check(Z3.mk_re_plus(contextPtr, this.ast))); + } + + star(): Re { + return new ReImpl(check(Z3.mk_re_star(contextPtr, this.ast))); + } + + option(): Re { + return new ReImpl(check(Z3.mk_re_option(contextPtr, this.ast))); + } + + complement(): Re { + return new ReImpl(check(Z3.mk_re_complement(contextPtr, this.ast))); + } + + union(other: Re): Re { + return new ReImpl(check(Z3.mk_re_union(contextPtr, [this.ast, other.ast]))); + } + + intersect(other: Re): Re { + return new ReImpl(check(Z3.mk_re_intersect(contextPtr, [this.ast, other.ast]))); + } + + diff(other: Re): Re { + return new ReImpl(check(Z3.mk_re_diff(contextPtr, this.ast, other.ast))); + } + + concat(other: Re): Re { + return new ReImpl(check(Z3.mk_re_concat(contextPtr, [this.ast, other.ast]))); + } + + loop(lo: number, hi: number = 0): Re { + return new ReImpl(check(Z3.mk_re_loop(contextPtr, this.ast, lo, hi))); + } + + power(n: number): Re { + return new ReImpl(check(Z3.mk_re_power(contextPtr, this.ast, n))); + } + } + class ArraySortImpl, RangeSort extends Sort> extends SortImpl implements SMTArraySort @@ -4731,6 +4911,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { FloatRM, String, Seq, + Re, Array, Set, Datatype, @@ -4823,6 +5004,23 @@ export function createApi(Z3: Z3Core): Z3HighLevel { FullSet, isMember, isSubset, + + InRe, + Union, + Intersect, + ReConcat, + Plus, + Star, + Option, + Complement, + Diff, + Range, + Loop, + Power, + AllChar, + Empty, + Full, + mkPartialOrder, mkTransitiveClosure, polynomialSubresultants, diff --git a/src/api/js/src/high-level/types.ts b/src/api/js/src/high-level/types.ts index b252f6921..fe00ace36 100644 --- a/src/api/js/src/high-level/types.ts +++ b/src/api/js/src/high-level/types.ts @@ -36,7 +36,8 @@ export type AnySort = | SMTArraySort | FPSort | FPRMSort - | SeqSort; + | SeqSort + | ReSort; /** @hidden */ export type AnyExpr = | Expr @@ -50,7 +51,8 @@ export type AnyExpr = | FP | FPNum | FPRM - | Seq; + | Seq + | Re; /** @hidden */ export type AnyAst = AnyExpr | AnySort | FuncDecl; @@ -70,6 +72,8 @@ export type SortToExprMap, Name extends string = 'main'> ? FPRM : S extends SeqSort ? Seq + : S extends ReSort + ? Re : S extends Sort ? Expr : never; @@ -458,6 +462,8 @@ export interface Context { /** @category Expressions */ readonly Seq: SeqCreation; /** @category Expressions */ + readonly Re: ReCreation; + /** @category Expressions */ readonly Array: SMTArrayCreation; /** @category Expressions */ readonly Set: SMTSetCreation; @@ -846,6 +852,55 @@ export interface Context { /** @category Operations */ isSubset>(a: SMTSet, b: SMTSet): Bool; + ////////////////////// + // Regular Expressions + ////////////////////// + + /** @category RegularExpression */ + InRe(seq: Seq | string, re: Re): Bool; + + /** @category RegularExpression */ + Union>(...res: Re[]): Re; + + /** @category RegularExpression */ + Intersect>(...res: Re[]): Re; + + /** @category RegularExpression */ + ReConcat>(...res: Re[]): Re; + + /** @category RegularExpression */ + Plus>(re: Re): Re; + + /** @category RegularExpression */ + Star>(re: Re): Re; + + /** @category RegularExpression */ + Option>(re: Re): Re; + + /** @category RegularExpression */ + Complement>(re: Re): Re; + + /** @category RegularExpression */ + Diff>(a: Re, b: Re): Re; + + /** @category RegularExpression */ + Range>(lo: Seq | string, hi: Seq | string): Re; + + /** @category RegularExpression */ + Loop>(re: Re, lo: number, hi?: number): Re; + + /** @category RegularExpression */ + Power>(re: Re, n: number): Re; + + /** @category RegularExpression */ + AllChar>(reSort: ReSort): Re; + + /** @category RegularExpression */ + Empty>(reSort: ReSort): Re; + + /** @category RegularExpression */ + Full>(reSort: ReSort): Re; + /** * Create a partial order relation over a sort. * @param sort The sort of the relation @@ -1641,7 +1696,8 @@ export interface Sort extends Ast { | DatatypeSort['__typename'] | FPSort['__typename'] | FPRMSort['__typename'] - | SeqSort['__typename']; + | SeqSort['__typename'] + | ReSort['__typename']; kind(): Z3_sort_kind; @@ -1768,6 +1824,7 @@ export interface Expr = AnySo | FP['__typename'] | FPRM['__typename'] | Seq['__typename'] + | Re['__typename'] | SMTArray['__typename'] | DatatypeExpr['__typename']; @@ -3129,6 +3186,80 @@ export interface Seq = replaceAll(src: Seq | string, dst: Seq | string): Seq; } +/////////////////////// +// Regular Expressions +/////////////////////// + +/** + * Regular expression sort + * @category RegularExpression + */ +export interface ReSort = SeqSort> extends Sort { + /** @hidden */ + readonly __typename: 'ReSort'; + + /** + * Get the basis (underlying sequence sort) of this regular expression sort + */ + basis(): SeqSortRef; + + cast(other: Re): Re; + cast(other: CoercibleToExpr): Expr; +} + +/** @category RegularExpression */ +export interface ReCreation { + /** + * Create a regular expression sort over the given sequence sort + */ + sort>(seqSort: SeqSortRef): ReSort; + + /** + * Convert a sequence to a regular expression that accepts exactly that sequence + */ + toRe(seq: Seq | string): Re; +} + +/** + * Regular expression expression + * @category RegularExpression + */ +export interface Re = SeqSort> + extends Expr, Z3_ast> { + /** @hidden */ + readonly __typename: 'Re'; + + /** @category Operations */ + plus(): Re; + + /** @category Operations */ + star(): Re; + + /** @category Operations */ + option(): Re; + + /** @category Operations */ + complement(): Re; + + /** @category Operations */ + union(other: Re): Re; + + /** @category Operations */ + intersect(other: Re): Re; + + /** @category Operations */ + diff(other: Re): Re; + + /** @category Operations */ + concat(other: Re): Re; + + /** @category Operations */ + loop(lo: number, hi?: number): Re; + + /** @category Operations */ + power(n: number): Re; +} + /** * Defines the expression type of the body of a quantifier expression *