feat(fls): write the system software of a .fls, loaded by Java as the original
topologyWriter.ts now sets the system software each device's constructor makes, through its setters: a switch's SSID and learning time, a host's SSID, RIP, manual routes, DHCP client and server with static assignments, static NAT, the modem, and a router's or home router's firewall. The firewall is reached as XMLEncoder reaches it, through the web server's `konfig` plug-in: the constructor hangs the same object there and among the applications, where its key differs (Firewall on a router, NatGateway on a home router). A switch's SSID the file lacked stays unwritten, so Java rolls one as it did. Files and applications are later layers. javaBeansWriter.ts: a call can carry statements on its result (a map's value changed through get(key)), checked by Java's XMLDecoder in a new case; a short() helper for Java's short values. Checked by Java against Java: every corpus file, read and written again, loads with the same system software (without files and applications) as the original. The synthetic topology adds what the corpus lacks: a router firewall switched on with rules of every protocol (one with a null address), every flag away from its default, a modem with its own port and target, and a PC's SSID, routes and DHCP server. 16 mutation probes, each rewritten and loaded by Java, were all caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,14 +59,15 @@ export type BeanStatement =
|
||||
| { readonly set: string; readonly value: BeanValue }
|
||||
/** target.getP(), then the statements on its result; `as` names the result */
|
||||
| { readonly get: string; readonly statements: readonly BeanStatement[]; readonly as?: BeanReference }
|
||||
/** target.m(args) */
|
||||
| { readonly call: string; readonly args: readonly BeanValue[] }
|
||||
/** target.m(args), then the statements on its result */
|
||||
| { readonly call: string; readonly args: readonly BeanValue[]; readonly statements?: readonly BeanStatement[] }
|
||||
/** target.set(index, value) on a list */
|
||||
| { readonly setIndex: number; readonly value: BeanValue }
|
||||
/** target.get(index), then the statements on its result; `as` names the result */
|
||||
| { readonly getIndex: number; readonly statements: readonly BeanStatement[]; readonly as?: BeanReference };
|
||||
|
||||
export const int = (value: number): BeanPrimitive => ({ kind: 'int', value });
|
||||
export const short = (value: number): BeanPrimitive => ({ kind: 'short', value });
|
||||
export const long = (value: number | bigint): BeanPrimitive => ({ kind: 'long', value });
|
||||
export const double = (value: number): BeanPrimitive => ({ kind: 'double', value });
|
||||
export const float = (value: number): BeanPrimitive => ({ kind: 'float', value });
|
||||
@@ -194,12 +195,14 @@ class Writer {
|
||||
} else if ('get' in statement) {
|
||||
this.getter(`property="${escapeAttribute(statement.get)}"`, statement.statements, statement.as, depth, lines);
|
||||
} else if ('call' in statement) {
|
||||
if (statement.args.length === 0) {
|
||||
const inner = statement.statements ?? [];
|
||||
if (statement.args.length === 0 && inner.length === 0) {
|
||||
lines.push(`${indent}<void method="${escapeAttribute(statement.call)}"/>`);
|
||||
return;
|
||||
}
|
||||
nested(`<void method="${escapeAttribute(statement.call)}"`, () => {
|
||||
for (const arg of statement.args) this.value(arg, depth + 1, lines);
|
||||
for (const each of inner) this.statement(each, depth + 1, lines);
|
||||
});
|
||||
} else if ('setIndex' in statement) {
|
||||
nested(`<void index="${statement.setIndex}"`, () => this.value(statement.value, depth + 1, lines));
|
||||
@@ -252,7 +255,10 @@ function sharedObjects(roots: readonly BeanValue[]): Set<BeanObject | BeanArray>
|
||||
const shared = new Set<BeanObject | BeanArray>();
|
||||
const visitStatement = (statement: BeanStatement): void => {
|
||||
if ('set' in statement || 'setIndex' in statement) visit(statement.value);
|
||||
else if ('call' in statement) statement.args.forEach(visit);
|
||||
else if ('call' in statement) {
|
||||
statement.args.forEach(visit);
|
||||
(statement.statements ?? []).forEach(visitStatement);
|
||||
}
|
||||
else statement.statements.forEach(visitStatement);
|
||||
};
|
||||
const visit = (value: BeanValue): void => {
|
||||
|
||||
Reference in New Issue
Block a user