@@ -2090,3 +2090,194 @@ def _to_sexpr_raw(self):
20902090 expr .append (formatter (value ))
20912091
20922092 return expr
2093+
2094+
2095+ @dataclass
2096+ class PadStackLayer :
2097+ name : str = ""
2098+
2099+ shape : str = ""
2100+
2101+ size : list [float ] = field (default_factory = lambda : [0 , 0 ])
2102+
2103+ rect_delta : list [float ] = field (default_factory = lambda : [0 , 0 ])
2104+
2105+ offset : list [float ] = field (default_factory = lambda : [0 , 0 ])
2106+
2107+ thermal_bridge_angle : Optional [float ] = None
2108+
2109+ thermal_gap : Optional [int ] = None
2110+
2111+ thermal_bridge_width : Optional [int ] = None
2112+
2113+ clearance : Optional [str ] = None
2114+
2115+ zone_connect : Optional [int ] = None
2116+
2117+ @classmethod
2118+ def from_sexpr (cls , exp : list ) -> PadStackLayer :
2119+ """Convert the given S-Expresstion into a PadStackLayer object
2120+
2121+ Args:
2122+ - exp (list): Part of parsed S-Expression ``(layer ...)``
2123+
2124+ Raises:
2125+ - Exception: When given parameter's type is not a list
2126+ - Exception: When the first item of the list is not generator
2127+
2128+ Returns:
2129+ - PadStackLayer: Object of the class initialized with the given S-Expression
2130+ """
2131+ if not isinstance (exp , list ):
2132+ raise Exception ("Expression does not have the correct type" )
2133+
2134+ if exp [0 ] != "layer" :
2135+ raise Exception ("Expression does not have the correct type" )
2136+
2137+ object = cls ()
2138+ object .name = exp [1 ]
2139+
2140+ for item in exp [2 :]:
2141+ if not isinstance (item , list ):
2142+ raise ValueError (
2143+ f"Expected list property [key, value], got: { item } . Full expression: { exp } "
2144+ )
2145+ elif item [0 ] == "shape" :
2146+ object .shape = item [1 ]
2147+ elif item [0 ] == "size" :
2148+ object .size = item [1 :]
2149+ elif item [0 ] == "rect_delta" :
2150+ object .rect_delta = item [1 :]
2151+ elif item [0 ] == "offset" :
2152+ object .offset = item [1 :]
2153+ elif item [0 ] == "thermal_bridge_angle" :
2154+ object .thermal_bridge_angle = item [1 ]
2155+ elif item [0 ] == "thermal_gap" :
2156+ object .thermal_gap = item [1 ]
2157+ elif item [0 ] == "thermal_bridge_width" :
2158+ object .thermal_bridge_width = item [1 ]
2159+ elif item [0 ] == "clearance" :
2160+ object .clearance = item [1 ]
2161+ elif item [0 ] == "zone_connect" :
2162+ object .zone_connect = item [1 ]
2163+ elif item [0 ] == "options" :
2164+ print ("Padstack layer options are still unsupported" )
2165+ continue
2166+ else :
2167+ raise ValueError (
2168+ f"Unrecognized property key: { item [0 ]} . Full expression: { item } "
2169+ )
2170+
2171+ return object
2172+
2173+ def to_sexpr (self , indent = 2 , newline = True ) -> str :
2174+ """Generate the S-Expression representing this object
2175+
2176+ Args:
2177+ - indent (int): Number of whitespaces used to indent the output. Defaults to 2.
2178+ - newline (bool): Adds a newline to the end of the output. Defaults to True.
2179+
2180+ Returns:
2181+ - str: S-Expression of this object
2182+ """
2183+ raw_expr = self ._to_sexpr_raw ()
2184+ return sexp_to_string (raw_expr )
2185+
2186+ def _to_sexpr_raw (self ):
2187+ expr = ["layer" , escape_and_quote (self .name )]
2188+
2189+ expr .append (["shape" , self .shape ])
2190+
2191+ expr .append (["size" , self .size [0 ], self .size [1 ]])
2192+
2193+ if self .rect_delta [0 ] != 0 or self .rect_delta [1 ] != 0 :
2194+ expr .append (["rect_delta" , self .rect_delta [0 ], self .rect_delta [1 ]])
2195+
2196+ if self .offset [0 ] != 0 or self .offset [1 ] != 0 :
2197+ expr .append (["offset" , self .offset [0 ], self .offset [1 ]])
2198+
2199+ # TODO options
2200+
2201+ if self .thermal_bridge_angle is not None :
2202+ expr .append (["thermal_bridge_angle" , self .thermal_bridge_angle ])
2203+
2204+ if self .thermal_gap is not None :
2205+ expr .append (["thermal_gap" , self .thermal_gap ])
2206+
2207+ if self .thermal_bridge_width is not None :
2208+ expr .append (["thermal_bridge_width" , self .thermal_bridge_width ])
2209+
2210+ if self .clearance is not None :
2211+ expr .append (["clearance" , self .clearance ])
2212+
2213+ if self .zone_connect is not None :
2214+ expr .append (["zone_connect" , self .zone_connect ])
2215+
2216+ return expr
2217+
2218+
2219+ @dataclass
2220+ class PadStack :
2221+ mode : str = ""
2222+
2223+ layers : dict [str , PadStackLayer ] = field (default_factory = dict )
2224+
2225+ @classmethod
2226+ def from_sexpr (cls , exp : list ) -> PadStack :
2227+ """Convert the given S-Expresstion into a PadStack object
2228+
2229+ Args:
2230+ - exp (list): Part of parsed S-Expression ``(padstack ...)``
2231+
2232+ Raises:
2233+ - Exception: When given parameter's type is not a list
2234+ - Exception: When the first item of the list is not generator
2235+
2236+ Returns:
2237+ - PadStack: Object of the class initialized with the given S-Expression
2238+ """
2239+ if not isinstance (exp , list ):
2240+ raise Exception ("Expression does not have the correct type" )
2241+
2242+ if exp [0 ] != "padstack" :
2243+ raise Exception ("Expression does not have the correct type" )
2244+
2245+ object = cls ()
2246+ for item in exp [1 :]:
2247+ if not isinstance (item , list ):
2248+ raise ValueError (
2249+ f"Expected list property [key, value], got: { item } . Full expression: { exp } "
2250+ )
2251+ elif item [0 ] == "mode" :
2252+ object .mode = item [1 ]
2253+ elif item [0 ] == "layer" :
2254+ object .layers [item [1 ]] = PadStackLayer .from_sexpr (item [1 ])
2255+ else :
2256+ raise ValueError (
2257+ f"Unrecognized property key: { item [0 ]} . Full expression: { item } "
2258+ )
2259+
2260+ return object
2261+
2262+ def to_sexpr (self , indent = 2 , newline = True ) -> str :
2263+ """Generate the S-Expression representing this object
2264+
2265+ Args:
2266+ - indent (int): Number of whitespaces used to indent the output. Defaults to 2.
2267+ - newline (bool): Adds a newline to the end of the output. Defaults to True.
2268+
2269+ Returns:
2270+ - str: S-Expression of this object
2271+ """
2272+ raw_expr = self ._to_sexpr_raw ()
2273+ return sexp_to_string (raw_expr )
2274+
2275+ def _to_sexpr_raw (self ):
2276+ expr = ["padstack" ]
2277+
2278+ expr .append (["mode" , self .mode ])
2279+
2280+ for layer in self .layers :
2281+ expr .append (layer ._to_sexpr_raw ())
2282+
2283+ return expr
0 commit comments