Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
414 changes: 218 additions & 196 deletions bun.lock

Large diffs are not rendered by default.

70 changes: 35 additions & 35 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,62 +20,62 @@
},
"dependencies": {
"@biomejs/biome": "1.9.4",
"@effect/cli": "0.54.1",
"@effect/opentelemetry": "0.42.7",
"@effect/platform": "0.75.1",
"@effect/platform-bun": "0.55.1",
"@effect/platform-node": "0.71.1",
"@opentelemetry/exporter-trace-otlp-http": "0.57.1",
"@effect/cli": "0.57.1",
"@effect/opentelemetry": "0.44.8",
"@effect/platform": "0.78.1",
"@effect/platform-bun": "0.58.1",
"@effect/platform-node": "0.74.1",
"@opentelemetry/exporter-trace-otlp-http": "0.57.2",
"@opentelemetry/sdk-metrics": "1.30.1",
"@opentelemetry/sdk-trace-base": "1.30.1",
"@opentelemetry/sdk-trace-node": "1.30.1",
"@opentelemetry/sdk-trace-web": "1.30.1",
"@tailwindcss/vite": "^4.0.6",
"@types/react": "^19.0.9",
"@types/react-dom": "^19.0.3",
"@tailwindcss/vite": "^4.0.12",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react-swc": "^3.8.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"effect": "3.12.7",
"effect": "3.13.8",
"eval": "0.1.8",
"lucide-react": "^0.475.0",
"lucide-react": "^0.479.0",
"nerdamer-prime": "^1.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.0.1",
"tailwind-merge": "^3.0.2",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@babel/cli": "7.26.4",
"@babel/core": "7.26.7",
"@babel/core": "7.26.9",
"@babel/plugin-transform-export-namespace-from": "7.25.9",
"@babel/plugin-transform-modules-commonjs": "7.26.3",
"@effect/build-utils": "0.7.8",
"@effect/eslint-plugin": "0.2.0",
"@effect/language-service": "0.2.0",
"@effect/vitest": "0.17.3",
"@eslint/compat": "1.2.5",
"@eslint/eslintrc": "3.2.0",
"@eslint/js": "9.19.0",
"@types/bun": "1.2.0",
"@types/node": "22.10.10",
"@typescript-eslint/eslint-plugin": "8.21.0",
"@typescript-eslint/parser": "8.21.0",
"@vitest/coverage-v8": "3.0.7",
"autoprefixer": "^10.4.20",
"@effect/build-utils": "0.7.9",
"@effect/eslint-plugin": "0.3.0",
"@effect/language-service": "0.4.0",
"@effect/vitest": "0.19.6",
"@eslint/compat": "1.2.7",
"@eslint/eslintrc": "3.3.0",
"@eslint/js": "9.22.0",
"@types/bun": "1.2.4",
"@types/node": "22.13.10",
"@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.26.0",
"@vitest/coverage-v8": "3.0.8",
"autoprefixer": "^10.4.21",
"babel-plugin-annotate-pure-calls": "0.5.0",
"eslint": "9.19.0",
"eslint-import-resolver-typescript": "3.7.0",
"eslint-plugin-codegen": "0.29.0",
"eslint": "9.22.0",
"eslint-import-resolver-typescript": "3.8.3",
"eslint-plugin-codegen": "0.30.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-sort-destructure-keys": "2.0.0",
"postcss": "^8.5.2",
"tailwindcss": "^4.0.6",
"tsx": "4.19.2",
"typescript": "5.7.3",
"vite": "^6.1.0",
"vitest": "3.0.4"
"postcss": "^8.5.3",
"tailwindcss": "^4.0.12",
"tsx": "4.19.3",
"typescript": "5.8.2",
"vite": "^6.2.1",
"vitest": "3.0.8"
},
"effect": {
"generateExports": {
Expand Down
1 change: 1 addition & 0 deletions src/schemas/built-in/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const BuiltInFunc = Schema.Literal(
"exp",
"pi",
"e",
"first",
);

export type BuiltInFunc = typeof BuiltInFunc.Type;
31 changes: 31 additions & 0 deletions src/schemas/diff/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// primitive schema
// int
// x
// x ** int
// int * x ** int
// sin(x)
// cos(x)
// tan(x)
// ln(x)
// exp(x)

import { Schema } from "effect";
import { InfixExp } from "../nodes/exps/infix";
import { IdentObj } from "../objs/ident";
import { IntegerObj } from "../objs/int";

// I want to answer the question:
// is this a primitive form?

// basically given obj and x.
// ask the questions:
// is obj the obj version of x
// is obj an infixObj with left x and right int
// is obj an infixobj with left int and right infix
// is obj a callobj with sin, cos, tan, ln, exp?

const PrimitiveDiff = Schema.Union(
IntegerObj,
IdentObj,
InfixExp, //
);
6 changes: 1 addition & 5 deletions src/scratch/two.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ import { Console, Effect } from "effect";
import { Schema } from "effect";
import { nativeToExp } from "src/schemas/nodes/exps/union";
import { ReturnStmt } from "src/schemas/nodes/stmts/return";
import {
type Stmt,
isExpStmt,
Stmt,
} from "src/schemas/nodes/stmts/union";
import { Stmt, isExpStmt } from "src/schemas/nodes/stmts/union";

const program = Effect.gen(function* () {
const istmt = nativeToExp(6);
Expand Down
3 changes: 3 additions & 0 deletions src/services/diff/interpret.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// I want to answer the question what is the function here?

// if I see (<complex exp>) ** <intObj>
2 changes: 1 addition & 1 deletion src/services/diff/obj.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BuiltInDiffFunc } from "@/schemas/built-in/diff";
import { CallExp } from "@/schemas/nodes/exps/call";
import { OpInfixExp } from "@/schemas/nodes/exps/infix";
import { nativeToIntExp } from "@/schemas/nodes/exps/int";
import { PrefixExp, opPrefixExp } from "@/schemas/nodes/exps/prefix";
import { opPrefixExp } from "@/schemas/nodes/exps/prefix";
import { BuiltInObj } from "@/schemas/objs/built-in";
import { BuiltInCallObj, CallObj } from "@/schemas/objs/call";
import { IdentObj } from "@/schemas/objs/ident";
Expand Down
11 changes: 8 additions & 3 deletions src/services/evaluator/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TokenType } from '../../schemas/token-types/union'
import { TokenType } from "../../schemas/token-types/union";

export const OPERATOR_TO_FUNCTION_MAP = {
[TokenType.PLUS]: (a: number, b: number) => a + b,
Expand All @@ -10,8 +10,13 @@ export const OPERATOR_TO_FUNCTION_MAP = {
[TokenType.GT]: (a: number, b: number) => a > b,
[TokenType.EQ]: <T>(a: T, b: T) => a === b,
[TokenType.NOT_EQ]: <T>(a: T, b: T) => a !== b,
} as const
} as const;

export const PREFIX_OPERATOR_TO_FUNCTION_MAP = {
[TokenType.BANG]: (a: number) => !a,
[TokenType.MINUS]: (a: number) => -a,
} as const;

export const STRING_OPERATOR_TO_FUNCTION_MAP = {
[TokenType.PLUS]: (a: string, b: string) => a + b,
} as const
} as const;
149 changes: 75 additions & 74 deletions src/services/lexer/state.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
import { Context, Effect, Layer, Ref } from 'effect'
import type { Token } from 'src/schemas/token/unions/all'
import { Context, Effect, Layer, Ref } from "effect";
import type { Token } from "src/schemas/token/unions/all";

export type LexerStateAll = Effect.Effect.Success<LexerState['getAll']>
export type LexerStateAll = Effect.Effect.Success<LexerState["getAll"]>;

export class LexerState {
incPos1: Effect.Effect<void>
decPos1: Effect.Effect<void>
getPos1: Effect.Effect<number>
incPos2: Effect.Effect<void>
getInput: Effect.Effect<string>
decPos2: Effect.Effect<void>
getPos2: Effect.Effect<number>
getChar: Effect.Effect<string>
setChar: (newChar: string) => Effect.Effect<void>
setPos1: (newPos: number) => Effect.Effect<void>
setPos2: (newPos2: number) => Effect.Effect<void>
setInput: (newInput: string) => Effect.Effect<void>
incPos1: Effect.Effect<void>;
decPos1: Effect.Effect<void>;
getPos1: Effect.Effect<number>;
incPos2: Effect.Effect<void>;
getInput: Effect.Effect<string>;
decPos2: Effect.Effect<void>;
getPos2: Effect.Effect<number>;
getChar: Effect.Effect<string>;
setChar: (newChar: string) => Effect.Effect<void>;
setPos1: (newPos: number) => Effect.Effect<void>;
setPos2: (newPos2: number) => Effect.Effect<void>;
setInput: (newInput: string) => Effect.Effect<void>;
getAll: Effect.Effect<{
input: string
pos1: number
pos2: number
char: string
}>
saveToken: (token: Token) => Effect.Effect<void>
getTokens: Effect.Effect<Token[]>
getPos1History: Effect.Effect<number[][]>
saveToPos1History: (pos1: number) => Effect.Effect<void>
getPos2History: Effect.Effect<number[][]>
saveToPos2History: (pos2: number) => Effect.Effect<void>
input: string;
pos1: number;
pos2: number;
char: string;
}>;
saveToken: (token: Token) => Effect.Effect<void>;
getTokens: Effect.Effect<Token[]>;
getPos1History: Effect.Effect<number[][]>;
saveToPos1History: (pos1: number) => Effect.Effect<void>;
getPos2History: Effect.Effect<number[][]>;
saveToPos2History: (pos2: number) => Effect.Effect<void>;

constructor(
// execution
Expand All @@ -40,80 +40,81 @@ export class LexerState {
private pos1History: Ref.Ref<number[][]>,
private pos2History: Ref.Ref<number[][]>,
) {
this.getInput = Ref.get(this.input)
this.getChar = Ref.get(this.char)
this.incPos1 = Ref.update(this.pos1, (n) => n + 1)
this.decPos1 = Ref.update(this.pos1, (n) => n - 1)
this.getPos1 = Ref.get(this.pos1)
this.incPos2 = Ref.update(this.pos2, (n) => n + 1)
this.decPos2 = Ref.update(this.pos2, (n) => n - 1)
this.getPos2 = Ref.get(this.pos2)
this.setChar = (newChar: string) => Ref.update(this.char, () => newChar)
this.setPos1 = (newPos1: number) => Ref.update(this.pos1, () => newPos1)
this.setPos2 = (newPos2: number) => Ref.update(this.pos2, () => newPos2)
this.getInput = Ref.get(this.input);
this.getChar = Ref.get(this.char);
this.incPos1 = Ref.update(this.pos1, (n) => n + 1);
this.decPos1 = Ref.update(this.pos1, (n) => n - 1);
this.getPos1 = Ref.get(this.pos1);
this.incPos2 = Ref.update(this.pos2, (n) => n + 1);
this.decPos2 = Ref.update(this.pos2, (n) => n - 1);
this.getPos2 = Ref.get(this.pos2);
this.setChar = (newChar: string) => Ref.update(this.char, () => newChar);
this.setPos1 = (newPos1: number) => Ref.update(this.pos1, () => newPos1);
this.setPos2 = (newPos2: number) => Ref.update(this.pos2, () => newPos2);
this.setInput = (newInput: string) =>
Effect.gen(function* () {
yield* Ref.set(input, newInput)
yield* Ref.set(pos1, 0)
yield* Ref.set(pos2, 1)
yield* Ref.set(char, newInput[0])
})
yield* Ref.set(input, newInput);
yield* Ref.set(pos1, 0);
yield* Ref.set(pos2, 1);
yield* Ref.set(char, newInput[0]);
});
this.getAll = Effect.gen(function* () {
return {
input: yield* Ref.get(input),
pos1: yield* Ref.get(pos1),
pos2: yield* Ref.get(pos2),
char: yield* Ref.get(char),
}
})
};
});

// Interpretability. TODO: From a perfomance persepective, this should be separate.
// FROM a performace perspective the only true zero-cost intepretability addition
// that is viable would be a clever wrapper thing. (apart from language level ability to fully turn off code.)
this.getTokens = Ref.get(this.tokens)
this.getTokens = Ref.get(this.tokens);
this.saveToken = (token: Token) =>
Ref.update(this.tokens, (tokens) => [...tokens, token])
this.getPos1History = Ref.get(this.pos1History)
this.getPos2History = Ref.get(this.pos2History)
Ref.update(this.tokens, (tokens) => [...tokens, token]);
this.getPos1History = Ref.get(this.pos1History);
this.getPos2History = Ref.get(this.pos2History);
this.saveToPos1History = (pos1: number) =>
Effect.gen(function* () {
const tks = yield* Ref.get(tokens)
const tks = yield* Ref.get(tokens);
yield* Ref.update(pos1History, (pos1History) => {
const tokensLength = tks.length
const tokensLength = tks.length;
if (!Array.isArray(pos1History[tokensLength])) {
pos1History.push([pos1])
pos1History.push([pos1]);
} else {
pos1History[tokensLength].push(pos1)
pos1History[tokensLength].push(pos1);
}
return pos1History
})
})
return pos1History;
});
});
this.saveToPos2History = (pos2: number) =>
Effect.gen(function* () {
const tks = yield* Ref.get(tokens)
const tks = yield* Ref.get(tokens);
yield* Ref.update(pos2History, (pos2History) => {
const tokensLength = tks.length
const tokensLength = tks.length;
if (!Array.isArray(pos2History[tokensLength])) {
pos2History.push([pos2])
pos2History.push([pos2]);
} else {
pos2History[tokensLength].push(pos2)
pos2History[tokensLength].push(pos2);
}
return pos2History
})
})
return pos2History;
});
});

// Interpretability
}

static make = (input: Ref.Ref<string>) =>
Effect.gen(function* () {
const pos1 = yield* Ref.make(0)
const pos2 = yield* Ref.make(1)
const pos1 = yield* Ref.make(0);
const pos2 = yield* Ref.make(1);
const char = yield* Ref.make(
yield* Ref.get(input).pipe(Effect.map((str) => str[0])),
)
const tokens = yield* Ref.make<Token[]>([])
const pos1History = yield* Ref.make<number[][]>([])
const pos2History = yield* Ref.make<number[][]>([])
);
const tokens = yield* Ref.make<Token[]>([]);
const pos1History = yield* Ref.make<number[][]>([]);
const pos2History = yield* Ref.make<number[][]>([]);

return new LexerState(
input,
Expand All @@ -123,21 +124,21 @@ export class LexerState {
tokens,
pos1History,
pos2History,
)
})
);
});
}

export class LexerStateService extends Context.Tag('LexerStateService')<
export class LexerStateService extends Context.Tag("LexerStateService")<
LexerStateService,
LexerState
>() {
static readonly make = (input: string) =>
Layer.effect(
this,
Effect.andThen(Ref.make(input), (inputRef) => LexerState.make(inputRef)),
)
);
static readonly Default = Layer.effect(
this,
Effect.andThen(Ref.make(''), (inputRef) => LexerState.make(inputRef)),
)
Effect.andThen(Ref.make(""), (inputRef) => LexerState.make(inputRef)),
);
}
Loading
Loading