slow.monster

STUDIO HAZE · jeniapp

Topaz source

Open by house policy. Topaz is our own language.

Topaz 5.20.2 · 63 files

apps/circuit/core/netlist.tpz

Topaz · 7330 B · Original file

1// 회로 그래프. 노드와 전선의 자료형, node 줄과 wire 줄 파서, 전선 검증을 둡니다.
2// node 아이디 종류 x y [값] 줄과 wire 시작:핀 끝:핀 줄을 토큰으로 받아 회로나 첫 오류 문구를 돌려줍니다.
3// 같은 입력이면 늘 같은 회로와 같은 오류가 나옵니다. 좌표는 표시용 값이고 신호 계산에 쓰지 않습니다.
4// 칩 계층과 평가는 다루지 않습니다. 그 일은 core.hierarchy 와 core.sim 이 합니다.
5// Circuit graph: node and wire types, node/wire line parsers and wire validation.
7import core.gate
8import core.util
10export type 노드종류 = "INPUT" | "OUTPUT" | "SEG7" | "NAND" | "AND" | "OR" | "NOT" | "XOR" | "NOR" | "XNOR"
11export type 노드 = { 아이디: string, 종류: 노드종류, x: int, y: int, 값: int }
12export type 전선 = { 시작노드: string, 시작핀: string, 끝노드: string, 끝핀: string }
13export type 회로 = { 노드들: Array<노드>, 전선들: Array<전선> }
14export type 입력값 = { 아이디: string, 값: int }
16type 끝점 = { 노드: string, 핀: string }
18export let 세그핀들 = ["in0", "in1", "in2", "in3", "in4", "in5", "in6"]
20function 노드종류로(토큰: string) -> Result<노드종류, string> {
21 match 토큰 {
22 case "INPUT" => Ok("INPUT")
23 case "OUTPUT" => Ok("OUTPUT")
24 case "SEG7" => Ok("SEG7")
25 case "NAND" => Ok("NAND")
26 case "AND" => Ok("AND")
27 case "OR" => Ok("OR")
28 case "NOT" => Ok("NOT")
29 case "XOR" => Ok("XOR")
30 case "NOR" => Ok("NOR")
31 case "XNOR" => Ok("XNOR")
32 case _ => Err("알 수 없는 게이트 종류입니다: " + 토큰)
33 }
36// 목록의 길이가 평가에 쓰는 입력 수입니다.
37export function 입력핀들(종류: 노드종류) -> Array<string> {
38 match 종류 {
39 case "INPUT" => []
40 case "OUTPUT" | "NOT" => ["in0"]
41 case "SEG7" => 세그핀들
42 case "NAND" | "AND" | "OR" | "XOR" | "NOR" | "XNOR" => ["in0", "in1"]
43 }
46function 출력핀인가(종류: 노드종류, 핀: string) -> bool {
47 match 종류 {
48 case "OUTPUT" | "SEG7" => false
49 case "INPUT" | "NAND" | "AND" | "OR" | "NOT" | "XOR" | "NOR" | "XNOR" => 핀 == "out"
50 }
53// SEG7 은 출력 핀이 없는 표시 장치라 자기 신호가 늘 꺼져 있습니다.
54export function 출력계산(종류: 노드종류, 가: bool, 나: bool) -> bool {
55 match 종류 {
56 case "INPUT" | "OUTPUT" => 가
57 case "SEG7" => false
58 case "NAND" => gate.부정논리곱(가, 나)
59 case "AND" => gate.논리곱(가, 나)
60 case "OR" => gate.논리합(가, 나)
61 case "NOT" => gate.부정(가)
62 case "XOR" => gate.배타적논리합(가, 나)
63 case "NOR" => gate.부정논리합(가, 나)
64 case "XNOR" => gate.배타적부정논리합(가, 나)
65 }
68export function 입력노드인가(종류: 노드종류) -> bool { 종류 == "INPUT" }
70export function 출력노드인가(종류: 노드종류) -> bool { 종류 == "OUTPUT" }
72// 같은 입력이 여럿이면 마지막 값을 씁니다. 목록에 없는 입력은 원래 값을 지킵니다.
73export function 입력적용(노드들: Array<노드>, 입력값들: Array<입력값>) -> Array<노드> {
74 let mut 값표: Map<string, int> = Map.new()
75 for 입력 in 입력값들 { 값표.insert(입력.아이디, 입력.값) }
76 노드들.map(노드값 => if 입력노드인가(노드값.종류) { 노드값{ 값: 값표.getOr(노드값.아이디, 노드값.값) } } else { 노드값 })
79// 값은 INPUT 에만 붙고 0 또는 1 입니다.
80function 노드줄파싱(토큰들: Array<string>) -> Result<노드, string> {
81 if 토큰들.length != 5 && 토큰들.length != 6 { return Err("node 줄 형식은 node 아이디 종류 x y [값] 입니다") }
82 if !util.안전아이디인가(토큰들[1]) { return Err("유효하지 않은 노드 아이디입니다: " + 토큰들[1]) }
83 let 종류 = 노드종류로(토큰들[2])?
84 if !util.정수인가(토큰들[3]) || !util.정수인가(토큰들[4]) { return Err("좌표는 정수여야 합니다") }
85 if 토큰들.length == 6 && !입력노드인가(종류) { return Err("값은 INPUT 노드에만 붙습니다") }
86 if 토큰들.length == 6 && 토큰들[5] != "0" && 토큰들[5] != "1" { return Err("입력 값은 0 또는 1이어야 합니다") }
87 Ok({
88 아이디: 토큰들[1],
89 종류: 종류,
90 x: toInt(토큰들[3]) ?? 0,
91 y: toInt(토큰들[4]) ?? 0,
92 값: if 토큰들.length == 6 && 토큰들[5] == "1" { 1 } else { 0 },
93 })
96function 끝점파싱(토큰: string) -> Result<끝점, string> {
97 let 부분 = 토큰.split(":")
98 if 부분.length != 2 || 부분[0] == "" || 부분[1] == "" { return Err("전선 끝점은 노드:핀 형식입니다") }
99 Ok({ 노드: 부분[0], 핀: 부분[1] })
102export function 전선줄파싱(토큰들: Array<string>) -> Result<전선, string> {
103 if 토큰들.length != 3 { return Err("wire 줄 형식은 wire 시작:핀 끝:핀 입니다") }
104 let 시작 = 끝점파싱(토큰들[1])?
105 let 끝 = 끝점파싱(토큰들[2])?
106 Ok({ 시작노드: 시작.노드, 시작핀: 시작.핀, 끝노드: 끝.노드, 끝핀: 끝.핀 })
109function 종류찾기(종류표: Map<string, 노드종류>, 아이디: string) -> Result<노드종류, string> {
110 match 종류표.get(아이디) {
111 case Some(종류) => Ok(종류)
112 case None => Err("전선이 없는 노드를 가리킵니다: " + 아이디)
113 }
116// 앞 전선부터 끝점과 핀을 보고, 모두 맞으면 한 입력 핀을 두 전선이 구동하는 첫 전선을 찾습니다.
117function 전선검증(노드들: Array<노드>, 전선들: Array<전선>) -> Result<회로, string> {
118 let mut 종류표: Map<string, 노드종류> = Map.new()
119 for 노드값 in 노드들 { 종류표.insert(노드값.아이디, 노드값.종류) }
120 for 선 in 전선들 {
121 let 시작종류 = 종류찾기(종류표, 선.시작노드)?
122 let 끝종류 = 종류찾기(종류표, 선.끝노드)?
123 if !출력핀인가(시작종류, 선.시작핀) { return Err("전선 시작은 출력 핀이어야 합니다: " + 선.시작노드 + ":" + 선.시작핀) }
124 if !(선.끝핀 in 입력핀들(끝종류)) { return Err("전선 끝은 입력 핀이어야 합니다: " + 선.끝노드 + ":" + 선.끝핀) }
125 }
126 let 핀키들 = 전선들.map(선 => 선.끝노드 + ":" + 선.끝핀)
127 let mut 구동수: Map<string, int> = Map.new()
128 for 핀키 in 핀키들 { 구동수.insert(핀키, 구동수.getOr(핀키, 0) + 1) }
129 let 겹친핀들 = 핀키들.filter(핀키 => 구동수.getOr(핀키, 0) > 1)
130 if 겹친핀들.length > 0 { return Err("한 입력 핀에 전선이 둘 이상입니다: " + 겹친핀들[0]) }
131 Ok({ 노드들: 노드들, 전선들: 전선들 })
134// node 줄을 차례로 읽어 첫 오류에서 멈추고, 그다음 전선을 검증합니다.
135export function 회로만들기(노드줄들: Array<Array<string>>, 전선들: Array<전선>) -> Result<회로, string> {
136 let mut 노드들: Array<노드> = []
137 let mut 본아이디들: Set<string> = Set.of()
138 for 토큰들 in 노드줄들 {
139 let 노드값 = 노드줄파싱(토큰들)?
140 if 노드값.아이디 in 본아이디들 { return Err("중복된 노드 아이디입니다: " + 노드값.아이디) }
141 본아이디들.add(노드값.아이디)
142 노드들.push(노드값)
143 }
144 전선검증(노드들, 전선들)

SHA256 62a5864acc5e2e38fd5380a17229e7526f72159442eef793e21376d7cb4a1511