Skip to content

Commit

Permalink
presentRuleAsNets
Browse files Browse the repository at this point in the history
  • Loading branch information
xieyuheng committed Aug 29, 2023
1 parent 8b48fda commit c9b067f
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 20 deletions.
6 changes: 3 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# present

`presentRuleInitialAsNet`
`presentWordAsEnv`

`presentRuleFinalAsNet`
# check

`presentWordAsEnv`
`checkAllLocalVariableAreUsed`

# articles

Expand Down
2 changes: 1 addition & 1 deletion src/lang/mod/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export * from "./defineRule"
export * from "./findNodeRuleEntries"
export * from "./lookupDefinition"
export * from "./lookupDefinitionOrFail"
export * from "./lookupRule"
export * from "./lookupRuleByNodes"
export * from "./lookupRuleByPorts"
17 changes: 17 additions & 0 deletions src/lang/mod/lookupRuleByName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Rule } from "../rule"
import { Mod } from "./Mod"
import { lookupDefinitionOrFail } from "./lookupDefinitionOrFail"
import { lookupRuleByNodes } from "./lookupRuleByNodes"

export function lookupRuleByName(mod: Mod, ruleName: string): Rule | undefined {
const [firstName, secondName] = ruleName.split(" ")

const firstDefinition = lookupDefinitionOrFail(mod, firstName)
const secondDefinition = lookupDefinitionOrFail(mod, secondName)

return lookupRuleByNodes(
mod,
{ url: firstDefinition.mod.url, name: firstDefinition.name },
{ url: secondDefinition.mod.url, name: secondDefinition.name },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { nodeKeyWithoutId } from "../node/nodeKeyWithoutId"
import { Rule } from "../rule"
import { Mod } from "./Mod"

export function lookupRule(
export function lookupRuleByNodes(
mod: Mod,
firstNode: NodeWithoutId,
secondNode: NodeWithoutId,
Expand Down
4 changes: 2 additions & 2 deletions src/lang/mod/lookupRuleByPorts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Port } from "../port"
import { Rule } from "../rule"
import { Mod } from "./Mod"
import { lookupRule } from "./lookupRule"
import { lookupRuleByNodes } from "./lookupRuleByNodes"

export function lookupRuleByPorts(
mod: Mod,
first: Port,
second: Port,
): Rule | undefined {
if (first.isPrincipal && second.isPrincipal) {
return lookupRule(mod, first.node, second.node)
return lookupRuleByNodes(mod, first.node, second.node)
}
}
9 changes: 8 additions & 1 deletion src/lang/net/clonePortEntry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { PortEntry } from "./Net"

export function clonePortEntry(entry: PortEntry): PortEntry {
return { ...entry }
return {
...entry,
connection: entry.connection
? {
...entry.connection,
}
: undefined,
}
}
8 changes: 7 additions & 1 deletion src/lang/net/clonePortRecord.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { PortRecord } from "./Net"
import { clonePortEntry } from "./clonePortEntry"

export function clonePortRecord(record: PortRecord): PortRecord {
return { ...record }
return Object.fromEntries(
Object.entries(record).map(([name, portEntry]) => [
name,
clonePortEntry(portEntry),
]),
)
}
4 changes: 3 additions & 1 deletion src/lang/net/disconnectPort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Port } from "../port"
import { Net } from "./Net"
import { findNodeEntry } from "./findNodeEntry"

export function disconnectPort(net: Net, port: Port): void {
export function disconnectPort(net: Net, port: Port): Port | undefined {
const nodeEntry = findNodeEntry(net, port.node)
if (nodeEntry === undefined) {
return undefined
Expand All @@ -14,4 +14,6 @@ export function disconnectPort(net: Net, port: Port): void {
if (connectedPort) {
disconnectPort(net, connectedPort)
}

return connectedPort
}
22 changes: 22 additions & 0 deletions src/lang/net/findPrincipalPort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Node, formatNode } from "../node"
import { Port } from "../port"
import { Net } from "./Net"
import { createPortFromPortEntry } from "./createPortFromPortEntry"
import { findPortRecordOrFail } from "./findPortRecordOrFail"

export function findPrincipalPort(net: Net, node: Node): Port {
const portRecord = findPortRecordOrFail(net, node)
for (const portEntry of Object.values(portRecord)) {
if (portEntry.isPrincipal) {
return createPortFromPortEntry(node, portEntry)
}
}

throw new Error(
[
`[findPrincipalPort] I expect the node to have a principal port.`,
``,
` node: ${formatNode(node)}`,
].join("\n"),
)
}
19 changes: 9 additions & 10 deletions src/lang/present/presentNodeAsNet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { presentNodeAsNet } from "./presentNodeAsNet"

test("presentNodeAsNet", async () => {
const text = `
type Nat -- Type end
node add
Nat :target!
Nat :addend
--------
Nat :return
end
type Nat -- Type end
node add
Nat :target!
Nat :addend
--------
Nat :return
end
`

Expand All @@ -23,9 +23,8 @@ test("presentNodeAsNet", async () => {
const url = new URL("test://presentNodeAsNet")
const mod = await loader.load(url, { text })
const net = presentNodeAsNet(mod, "add")
const output = formatNet(net)

expect(output).toMatchInlineSnapshot(`
expect(formatNet(net)).toMatchInlineSnapshot(`
"(add₀)-addend covering-(@input_port_cap₀)
(add₀)-return covering-(@ouput_port_cap₀)"
`)
Expand Down
62 changes: 62 additions & 0 deletions src/lang/present/presentRuleAsNets.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { expect, test } from "vitest"
import { Fetcher } from "../../fetcher"
import { Loader } from "../../loader"
import { formatNet } from "../net/formatNet"
import { presentRuleAsNets } from "./presentRuleAsNets"

test("presentRuleAsNets", async () => {
const text = `
type Nat -- Type end
node zero
------
Nat :value!
end
node add1
Nat :prev
----------
Nat :value!
end
node add
Nat :target!
Nat :addend
--------
Nat :return
end
rule zero add
(add)-addend
return-(add)
end
rule add1 add
(add)-addend
(add1)-prev add
add1 return-(add)
end
`

const fetcher = new Fetcher()
const loader = new Loader({ fetcher })
const url = new URL("test://presentRuleAsNets")
const mod = await loader.load(url, { text })
const [initial, final] = presentRuleAsNets(mod, "add1 add")

expect(formatNet(initial)).toMatchInlineSnapshot(`
"(add1₂)-prev covering-(@input_port_cap₃)
(add1₂)-value!target-(add₃)
(add₃)-addend covering-(@input_port_cap₄)
(add₃)-return covering-(@ouput_port_cap₂)"
`)

expect(formatNet(final)).toMatchInlineSnapshot(`
"(@input_port_cap₃)-covering!target-(add₄)
(@input_port_cap₄)-covering addend-(add₄)
(@ouput_port_cap₂)-covering!value-(add1₃)
(add₄)-return prev-(add1₃)"
`)
})
77 changes: 77 additions & 0 deletions src/lang/present/presentRuleAsNets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { capNode } from "../cap"
import { compose } from "../compose/compose"
import { connect } from "../connect/connect"
import { createEnv } from "../env/createEnv"
import { Mod, lookupDefinitionOrFail } from "../mod"
import { lookupRuleByName } from "../mod/lookupRuleByName"
import { Net, copyConnectedComponent, createNet } from "../net"
import { deleteNodeEntry } from "../net/deleteNodeEntry"
import { disconnectPort } from "../net/disconnectPort"
import { findPrincipalPort } from "../net/findPrincipalPort"
import { Node } from "../node"
import { createNodeFromDefinition } from "../node/createNodeFromDefinition"

export function presentRuleAsNets(mod: Mod, ruleName: string): [Net, Net] {
const env = createEnv(mod)

const rule = lookupRuleByName(mod, ruleName)
if (rule === undefined) {
throw new Error(
[
`[presentRuleAsNets] I meet undefined rule.`,
``,
` ruleName: ${ruleName}`,
].join("\n"),
)
}

const [firstName, secondName] = ruleName.split(" ")

const first = createNodeFromDefinition(
env.net,
lookupDefinitionOrFail(mod, firstName),
)

const second = createNodeFromDefinition(
env.net,
lookupDefinitionOrFail(mod, secondName),
)

capNode(mod, env.net, first)
capNode(mod, env.net, second)

const initial = collectInitialNet(env.net, first, second)

for (const word of rule.words) {
compose(mod, env, word, {
current: { first, second },
})
}

const final = env.net

return [initial, final]
}

function collectInitialNet(net: Net, first: Node, second: Node): Net {
const initial = createNet()

copyConnectedComponent(net, initial, first)
copyConnectedComponent(net, initial, second)

const firstPrincipalPort = findPrincipalPort(initial, first)
const firstConnectedPort = disconnectPort(initial, firstPrincipalPort)
if (firstConnectedPort) {
deleteNodeEntry(initial, firstConnectedPort.node)
}

const secondPrincipalPort = findPrincipalPort(initial, second)
const secondConnectedPort = disconnectPort(initial, secondPrincipalPort)
if (secondConnectedPort) {
deleteNodeEntry(initial, secondConnectedPort.node)
}

connect(initial, firstPrincipalPort, secondPrincipalPort)

return initial
}

0 comments on commit c9b067f

Please sign in to comment.