Skip to content
Merged
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
3 changes: 2 additions & 1 deletion ddss/dump.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import asyncio
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds_bnf import unparse
from .orm import Facts, Ideas


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
async with session() as sess:
for i in await sess.scalars(select(Ideas)):
Expand Down
8 changes: 2 additions & 6 deletions ddss/dump.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import type { Sequelize } from "sequelize";
import { unparse } from "atsds-bnf";
import { Fact, Idea, initializeDatabase } from "./orm.ts";

export async function main(addr: string, sequelize?: Sequelize) {
if (!sequelize) {
sequelize = await initializeDatabase(addr);
}
import { Fact, Idea } from "./orm.ts";

export async function main(sequelize: Sequelize): Promise<void> {
const ideas = await Idea.findAll();
for (const idea of ideas) {
console.log("idea:", unparse(idea.data));
Expand Down
3 changes: 2 additions & 1 deletion ddss/egg.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import asyncio
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds import Rule
from .orm import insert_or_ignore, Facts, Ideas
from .egraph import Search


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
search = Search()
pool = []
Expand Down
4 changes: 2 additions & 2 deletions ddss/egg.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Op, type Sequelize } from "sequelize";
import { Rule } from "atsds";
import { Search } from "./egraph.ts";
import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts";
import { Fact, Idea, insertOrIgnore } from "./orm.ts";

export async function main(sequelize: Sequelize) {
export async function main(sequelize: Sequelize): Promise<void> {
const search = new Search();
let pool: Rule[] = [];
let maxFact = -1;
Expand Down
11 changes: 6 additions & 5 deletions ddss/egraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ function extractLhsRhsFromRule(data: Rule): [Term, Term] | null {
if (data.length() !== 0) {
return null;
}
const term = data.conclusion();
const inner = term.term();
if (!(inner instanceof List)) {
const term = data.conclusion().term();
if (!(term instanceof List)) {
return null;
}
if (!(inner.length() === 4 && inner.getitem(0).toString() === "binary" && inner.getitem(1).toString() === "==")) {
if (!(term.length() === 4 && term.getitem(0).toString() === "binary" && term.getitem(1).toString() === "==")) {
return null;
}
return [inner.getitem(2), inner.getitem(3)];
const lhs = term.getitem(2);
const rhs = term.getitem(3);
return [lhs, rhs];
}

function buildLhsRhsToTerm(lhs: Term, rhs: Term): Term {
Expand Down
7 changes: 3 additions & 4 deletions ddss/input.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import asyncio
from prompt_toolkit import PromptSession
from prompt_toolkit.patch_stdout import patch_stdout
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds_bnf import parse
from .orm import insert_or_ignore, Facts, Ideas
from .utility import str_rule_get_str_idea


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
prompt = PromptSession()
while True:
Expand All @@ -17,9 +18,7 @@ async def main(session):
raise asyncio.CancelledError()

data = line.strip()
if data == "":
continue
if data.startswith("//"):
if data == "" or data.startswith("//"):
continue

try:
Expand Down
9 changes: 4 additions & 5 deletions ddss/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";
import type { Sequelize } from "sequelize";
import { parse } from "atsds-bnf";
import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts";
import { Fact, Idea, insertOrIgnore } from "./orm.ts";
import { patchStdout, strRuleGetStrIdea } from "./utility.ts";

export async function main(sequelize: Sequelize) {
export async function main(sequelize: Sequelize): Promise<void> {
const rl = readline.createInterface({ input, output });
rl.setPrompt("input: ");
const unpatch = patchStdout(rl);
Expand All @@ -21,10 +21,9 @@ export async function main(sequelize: Sequelize) {

try {
const ds = parse(data);
const dsStr = ds.toString();

await insertOrIgnore(Fact, dsStr);
const idea = strRuleGetStrIdea(dsStr);
await insertOrIgnore(Fact, ds);
const idea = strRuleGetStrIdea(ds);
if (idea) {
await insertOrIgnore(Idea, idea);
Comment on lines 23 to 28

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as in load.ts: insertOrIgnore and strRuleGetStrIdea both take string, but this code passes the parse() result directly. Convert the parsed value to a string (e.g., ds.toString()) before inserting/extracting the idea.

Copilot uses AI. Check for mistakes.
}
Expand Down
7 changes: 3 additions & 4 deletions ddss/load.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import asyncio
import sys
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds_bnf import parse
from .orm import insert_or_ignore, Facts, Ideas
from .utility import str_rule_get_str_idea


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
async with session() as sess:
for line in sys.stdin:
data = line.strip()
if data == "":
continue
if data.startswith("//"):
if data == "" or data.startswith("//"):
continue

try:
Expand Down
9 changes: 4 additions & 5 deletions ddss/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import * as readline from "node:readline/promises";
import { stdin as input } from "node:process";
import type { Sequelize } from "sequelize";
import { parse } from "atsds-bnf";
import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts";
import { Fact, Idea, insertOrIgnore } from "./orm.ts";
import { strRuleGetStrIdea } from "./utility.ts";

export async function main(sequelize: Sequelize) {
export async function main(sequelize: Sequelize): Promise<void> {
const rl = readline.createInterface({
input,
terminal: false,
Expand All @@ -19,10 +19,9 @@ export async function main(sequelize: Sequelize) {

try {
const ds = parse(data);
const dsStr = ds.toString();

await insertOrIgnore(Fact, dsStr);
const idea = strRuleGetStrIdea(dsStr);
await insertOrIgnore(Fact, ds);
const idea = strRuleGetStrIdea(ds);
if (idea) {
await insertOrIgnore(Idea, idea);
Comment on lines 21 to 26

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse() returns a non-string value here, but insertOrIgnore expects data: string and strRuleGetStrIdea expects data: string. Passing ds directly will fail type-checking (and likely store [object Object] at runtime). Convert ds to a string before inserting/deriving the idea (e.g., use ds.toString() consistently as in other modules).

Copilot uses AI. Check for mistakes.
}
Expand Down
7 changes: 4 additions & 3 deletions ddss/main.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import asyncio
import tempfile
import pathlib
from typing import Annotated, Optional
from typing import Annotated, Optional, Awaitable
import tyro
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from .orm import initialize_database
from .search import main as search
from .egg import main as egg
Expand All @@ -11,7 +12,7 @@
from .load import main as load
from .dump import main as dump

component_map = {
component_map: dict[str, callable[[async_sessionmaker[AsyncSession]], Awaitable[None]]] = {
"search": search,
"egg": egg,
"input": input,
Comment on lines +15 to 18

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type annotation uses callable[...], but callable is a built-in function, not a typing construct. This will fail type checking. Use typing.Callable[[async_sessionmaker[AsyncSession]], Awaitable[None]] (and import Callable) for component_map’s value type.

Copilot uses AI. Check for mistakes.
Expand All @@ -29,7 +30,7 @@ async def run(addr: str, components: list[str]) -> None:
coroutines = [component_map[component](session) for component in components]
except KeyError as e:
print(f"error: unsupported component: {str(e)}")
raise asyncio.CancelledError()
return

await asyncio.wait(
[asyncio.create_task(coro) for coro in coroutines],
Expand Down
12 changes: 6 additions & 6 deletions ddss/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { main as load } from "./load.ts";
import { main as output } from "./output.ts";
import { initializeDatabase } from "./orm.ts";

type ComponentMain = (addr: string, sequelize: Sequelize) => Promise<void>;
type ComponentMain = (sequelize: Sequelize) => Promise<void>;

const componentMap: Record<string, ComponentMain> = {
search,
Expand All @@ -22,27 +22,27 @@ const componentMap: Record<string, ComponentMain> = {
dump,
};

async function run(addr: string, components: string[]) {
async function run(addr: string, components: string[]): Promise<void> {
const sequelize = await initializeDatabase(addr);

for (const name of components) {
if (!(name in componentMap)) {
console.error(`error: unsupported component: ${name}`);
return;
}
}
Comment on lines +25 to 33

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializeDatabase(addr) is executed before validating components. If an unsupported component is provided, run() returns early without closing the Sequelize connection, leaking resources and possibly leaving a temp DB file locked. Validate components before initializing the database, or ensure sequelize.close() runs on all early-return paths (e.g., via try/finally).

Copilot uses AI. Check for mistakes.

const sequelize = await initializeDatabase(addr);

const promises = components.map((name) => {
const component = componentMap[name]!;
return component(addr, sequelize);
return component(sequelize);
});

await Promise.race(promises);

await sequelize.close();
}

export function cli() {
export async function cli(): Promise<void> {
const program = new Command();

program
Expand Down
1 change: 0 additions & 1 deletion ddss/orm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
type CreationOptional,
type InferAttributes,
type InferCreationAttributes,
type ModelStatic,
} from "sequelize";

class Fact extends Model<InferAttributes<Fact>, InferCreationAttributes<Fact>> {
Expand Down
3 changes: 2 additions & 1 deletion ddss/output.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import asyncio
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds_bnf import unparse
from .orm import Facts, Ideas


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
max_fact = -1
max_idea = -1
Expand Down
4 changes: 2 additions & 2 deletions ddss/output.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Op, type Sequelize } from "sequelize";
import { unparse } from "atsds-bnf";
import { Fact, Idea, initializeDatabase } from "./orm.ts";
import { Fact, Idea } from "./orm.ts";

export async function main(sequelize: Sequelize) {
export async function main(sequelize: Sequelize): Promise<void> {
let maxFact = -1;
let maxIdea = -1;

Expand Down
3 changes: 2 additions & 1 deletion ddss/search.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import asyncio
from sqlalchemy import select
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from apyds import Search
from .orm import insert_or_ignore, Facts, Ideas
from .utility import str_rule_get_str_idea


async def main(session):
async def main(session: async_sessionmaker[AsyncSession]) -> None:
try:
search = Search()
max_fact = -1
Expand Down
10 changes: 5 additions & 5 deletions ddss/search.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Op, type Sequelize } from "sequelize";
import { Search } from "atsds";
import type { Rule } from "atsds";
import { Fact, Idea, initializeDatabase, insertOrIgnore } from "./orm.ts";
import { Fact, Idea, insertOrIgnore } from "./orm.ts";
import { strRuleGetStrIdea } from "./utility.ts";

export async function main(sequelize: Sequelize) {
export async function main(sequelize: Sequelize): Promise<void> {
const search = new Search();
let maxFact = -1;

Expand All @@ -21,9 +21,9 @@ export async function main(sequelize: Sequelize) {
const tasks: Promise<void>[] = [];

const handler = (rule: Rule) => {
const dsStr = rule.toString();
tasks.push(insertOrIgnore(Fact, dsStr));
const idea = strRuleGetStrIdea(dsStr);
const ds = rule.toString();
tasks.push(insertOrIgnore(Fact, ds));
const idea = strRuleGetStrIdea(ds);
if (idea) {
tasks.push(insertOrIgnore(Idea, idea));
}
Expand Down
2 changes: 1 addition & 1 deletion ddss/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function strRuleGetStrIdea(data: string): string | null {
return null;
}

export function patchStdout(rl: Interface) {
export function patchStdout(rl: Interface): () => void {
const originalWrite = stdout.write;
const originalLog = console.log;
const originalError = console.error;
Expand Down
Loading