Skip to content

Commit

Permalink
Basic operator checking (#186)
Browse files Browse the repository at this point in the history
- Basic operator checking (fixes #92)
- Inequality checks with ranges
- Identity checks from disjoint with `NaN`
- Disjoint with `Not` works (using subtyping)
- Proper checking that allows string + number?
- `infer T` in type annotation slice gets treated as `infer T extends string` (and also for generic arguments)
- Add `Number.isNaN` checks
- Change `GreaterThan` and `LessThan` to `InclusiveRange` and `ExclusiveRange`
- Add operations to ranges with new `FloatRange` type
- Changes `~`, `!` and `-` prefix operators to be in terms of `x ^ 0xFFFF_FFFF`, `x ? false : true` and `0 - x`. Removes `Constructor::UnaryOperation`
- Fixes to narrowing for `if (a)` where a is `string | falsy etc` and also to optional chaining
- Moves `a + b` is string or number to `result` field on `Constructor::BinaryOperator { result }` 
- Refactor of type helpers
- Type parameter extends checking on arguments
  • Loading branch information
kaleidawave authored Aug 26, 2024
1 parent c952b6d commit e69e2c5
Show file tree
Hide file tree
Showing 49 changed files with 2,448 additions and 1,215 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Examples

on:
push:
branches: [main]
workflow_dispatch:

env:
CARGO_TERM_COLOR: always

jobs:
run-examples:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

- name: Build Ezno
run: cargo build --release
env:
CARGO_PROFILE_RELEASE_DEBUG: true

- name: Run checker on example files
shell: bash
run: |
files=(
"https://jsr.io/@yossydev/hello-world/1.0.0/index.ts"
"https://jsr.io/@bengineering/shuffle-binary/0.0.1/index.ts"
"https://jsr.io/@bengineering/mulberry32/0.0.1/mod.ts"
"https://jsr.io/@luca/cases/1.0.0/mod.ts"
"https://jsr.io/@std/assert/1.0.2/assertion_error.ts"
"https://jsr.io/@std/text/1.0.3/levenshtein_distance.ts"
"https://jsr.io/@gnome/monads/0.0.0/src/option.ts"
"https://raw.githubusercontent.com/getify/deePool/master/src/deePool.js"
"https://raw.githubusercontent.com/silen-z/fiveway/main/packages/fiveway/src/id.ts"
)
for url in "${files[@]}"; do
header="--- $url ---"
echo $header
curl -s $url > temp.ts
./target/release/ezno check temp.ts --timings
echo "${header//?/-}"
echo ""
done
2 changes: 2 additions & 0 deletions .github/workflows/performance-and-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
cargo run -p ezno-parser --example code_blocks_to_script all.md --comment-headers --out ./all.tsx
./target/release/ezno check all.tsx --timings || true
hyperfine -i './target/release/ezno check all.tsx'
echo "::endgroup::"
- name: Run checker performance on large file
Expand All @@ -108,6 +109,7 @@ jobs:
done
./target/release/ezno check large.tsx --timings --max-diagnostics 0 || true
hyperfine -i './target/release/ezno check large.tsx'
echo "::endgroup::"
- name: Run parsing & stringing (minfied) benchmarks
Expand Down
Binary file modified checker/definitions/internal.ts.d.bin
Binary file not shown.
40 changes: 33 additions & 7 deletions checker/definitions/overrides.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ declare class Array<T> {
let i: number = 0;
while (i < length) {
const value = this[i];
if (!cb(value, i++)) {
const result = cb(value, i++) as boolean;
if (!result) {
return false
}
}
Expand All @@ -103,10 +104,10 @@ declare class Array<T> {
if (length === 0) {
return ""
}
let s: string = "" + this[0];
let s: string = "" + (this[0] as string);
while (i < length) {
s += joiner;
s += this[i++];
s += this[i++] as string;
}
return s
}
Expand All @@ -118,20 +119,28 @@ declare class Array<T> {
return this[index]
}
}

static isArray(item: any) {
return item instanceof Array;
}
}

type Record<K extends string, T> = { [P in K]: T }

type LessThan<T extends number> = ExclusiveRange<NegativeInfinity, T>;
type GreaterThan<T extends number> = ExclusiveRange<T, Infinity>;
type Integer = MultipleOf<1>;

declare class Map<T, U> {
#keys: Array<T> = [];
#value: Array<T> = [];
}

declare class Math {
@Constant
static sin(x: number): number;
static sin(x: number): InclusiveRange<-1, 1>;
@Constant
static cos(x: number): number;
static cos(x: number): InclusiveRange<-1, 1>;
@Constant
static tan(x: number): number;
@Constant
Expand All @@ -147,11 +156,14 @@ declare class Math {
@Constant
static trunc(x: number): number;

@Constant
static imul(x: number, y: number): number;

static PI: 3.141592653589793
static E: 2.718281828459045

@InputOutput
static random(): number;
static random(): InclusiveRange<0, 1>;
}

@Primitive("string")
Expand All @@ -172,6 +184,20 @@ declare class String {
split(splitter: string): Array<string>;
}

@Primitive("number")
declare class Number {
static NEGATIVE_INFINITY: NegativeInfinity;
static POSITIVE_INFINITY: Infinity;

// static isFinite(item: any) {
// return !(item === Number.NEGATIVE_INFINITY || item === Number.POSITIVE_INFINITY || Number.isNaN(item))
// }

static isNaN(item: any) {
return item !== item;
}
}

declare class Promise<T> { }

declare class RegExp {
Expand Down Expand Up @@ -377,7 +403,7 @@ declare class Object {
return entries
}

// TODO multiple arguments
// TODO spread source
static assign(target: object, source: object): object {
for (const key in source) {
target[key] = source[key]
Expand Down
38 changes: 32 additions & 6 deletions checker/definitions/simple.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ declare function debug_state(): void

// A function, as it should be!
@Constant
declare function satisfies<T>(t: T): T
declare function satisfies<YE>(t: YE): YE

interface ImportEnv {
[key: string]: string;
Expand Down Expand Up @@ -75,7 +75,7 @@ declare class Array<T> {
map<U>(cb: (t: T, i?: number) => U): Array<U> {
const { length } = this, mapped: Array<U> = [];
let i: number = 0;
while (i < length) {
while (i < (length as number)) {
const value = this[i];
const newValue = cb(value, i++);
mapped.push(newValue)
Expand Down Expand Up @@ -176,6 +176,11 @@ declare class Array<T> {
// return this[index]
// }
// }

/// TODO incorrect definition, doesn't account for realms
static isArray(item: any) {
return item instanceof Array;
}
}

declare class Map<K, V> {
Expand Down Expand Up @@ -206,6 +211,10 @@ declare class Map<K, V> {

type Record<K extends string, T> = { [P in K]: T }

type LessThan<T extends number> = ExclusiveRange<NegativeInfinity, T>;
type GreaterThan<T extends number> = ExclusiveRange<T, Infinity>;
type Integer = MultipleOf<1>;

/**
* Exclude from T those types that are assignable to U
*/
Expand All @@ -218,9 +227,9 @@ type Extract<T, U> = T extends U ? T : never;

declare class Math {
@Constant
static sin(x: number): number;
static sin(x: number): InclusiveRange<-1, 1>;
@Constant
static cos(x: number): number;
static cos(x: number): InclusiveRange<-1, 1>;
@Constant
static tan(x: number): number;
@Constant
Expand All @@ -232,15 +241,18 @@ declare class Math {
@Constant
static log(x: number): number;

// TODO newer method
// TODO newer methods
@Constant
static trunc(x: number): number;

@Constant
static imul(x: number, y: number): number;

static PI: 3.141592653589793
static E: 2.718281828459045

@InputOutput
static random(): number;
static random(): 0 | InclusiveRange<0, 1>;
}

@Primitive("string")
Expand All @@ -261,6 +273,20 @@ declare class String {
split(splitter: string): Array<string>;
}

@Primitive("number")
declare class Number {
static NEGATIVE_INFINITY: NegativeInfinity;
static POSITIVE_INFINITY: Infinity;

// static isFinite(item: any) {
// return !(item === Number.NEGATIVE_INFINITY || item === Number.POSITIVE_INFINITY || Number.isNaN(item))
// }

static isNaN(item: any) {
return item !== item;
}
}

declare class Promise<T> { }

type ResponseBody = string;
Expand Down
2 changes: 1 addition & 1 deletion checker/examples/run_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ fn main() {
let end = now.elapsed();
let count = result.diagnostics.into_iter().len();
eprintln!("Found {count} diagnostics in {end:?}");
} else if args.iter().any(|arg| arg == "--debug-diagnostics") {
} else if args.iter().any(|arg| arg == "--verbose-diagnostics") {
eprintln!("Diagnostics:");
for diagnostic in result.diagnostics {
eprintln!("{diagnostic:?}");
Expand Down
2 changes: 1 addition & 1 deletion checker/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "ezno-parser-fuzz"
name = "ezno-checker-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
Expand Down
Loading

0 comments on commit e69e2c5

Please sign in to comment.