import gleam/list import gleam/option.{type Option, None, Some} import gleam/pair import kicad_sexpr/decode.{type Decoder, type NextFn} fn width(then next: NextFn(Float, a)) -> Decoder(a) { decode.token_wrapper(named: "width", with: decode.float, then: next) } fn thickness(then next: NextFn(Float, a)) -> Decoder(a) { decode.token_wrapper(named: "thickness", with: decode.float, then: next) } fn yes_no(then next: NextFn(Bool, a)) -> Decoder(a) { decode.enum(with: [#("yes", True), #("no", False)], then: next) } fn allowed(then next: NextFn(Bool, a)) -> Decoder(a) { decode.enum(with: [#("allowed", True), #("not_allowed", False)], then: next) } fn filled(then next: NextFn(Bool, a)) -> Decoder(a) { decode.token_wrapper(named: "fill", with: yes_no, then: next) } fn angle(then next: NextFn(Float, a)) -> Decoder(a) { decode.token_wrapper(named: "angle", with: decode.float, then: next) } fn corners(then next: NextFn(#(XY, XY, XY, XY), a)) -> Decoder(a) { decode.token(named: "pts", then: next, with: { use xy1 <- xy() use xy2 <- xy() use xy3 <- xy() use xy4 <- xy() decode.success(#(xy1, xy2, xy3, xy4)) }) } fn margins(then next: NextFn(#(Float, Float, Float, Float), a)) -> Decoder(a) { decode.token( named: "margins", with: { use f1 <- decode.float() use f2 <- decode.float() use f3 <- decode.float() use f4 <- decode.float() decode.success(#(f1, f2, f3, f4)) }, then: next, ) } fn hide(then next: NextFn(Bool, a)) -> Decoder(a) { decode.one_of( decode.token_wrapper(named: "hide", with: yes_no, then: _), or: [decode.flag("hide", then: _)], then: next, ) } fn custom_xy(named name: String, then next: NextFn(XY, a)) -> Decoder(a) { decode.token(named: name, then: next, with: { use x <- decode.float() use y <- decode.float() decode.success(XY(x:, y:)) }) } fn layers(then next: NextFn(List(Layer), a)) -> Decoder(a) { decode.token(named: "layers", then: next, with: { use layers <- decode.list(decode.name_string) let layers = list.map(layers, Layer) decode.success(layers) }) } pub type PositionIdentifier { PositionIdentifier( x: Float, y: Float, angle: Option(Float), locked: Option(Bool), ) } pub fn position_identifier( then next: NextFn(PositionIdentifier, a), ) -> Decoder(a) { decode.token(named: "at", then: next, with: { use x <- decode.float() use y <- decode.float() use angle <- decode.optional(decode.float) use locked <- decode.optional(decode.enum( [#("locked", True), #("unlocked", False)], then: _, )) decode.success(PositionIdentifier(x:, y:, angle:, locked:)) }) } pub type XY { XY(x: Float, y: Float) } pub fn xy(then next: NextFn(XY, a)) -> Decoder(a) { decode.token(named: "xy", then: next, with: { use x <- decode.float() use y <- decode.float() decode.success(XY(x:, y:)) }) } pub type XYZ { XYZ(x: Float, y: Float, z: Float) } pub fn xyz(then next: NextFn(XYZ, a)) -> Decoder(a) { decode.token(named: "xyz", then: next, with: { use x <- decode.float() use y <- decode.float() use z <- decode.float() decode.success(XYZ(x:, y:, z:)) }) } pub type Line { Line(points: Points) } pub fn line(then next: NextFn(Line, a)) -> Decoder(a) { decode.token(named: "polyline", then: next, with: { use points <- points() decode.success(Line(points:)) }) } pub type Rectangle { Rectangle(start: XY, end: XY) } pub fn rectangle(then next: NextFn(Rectangle, a)) -> Decoder(a) { decode.token(named: "rectangle", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") decode.success(Rectangle(start:, end:)) }) } pub type Circle { Circle(center: XY, radius: Float) } pub fn circle(then next: NextFn(Circle, a)) -> Decoder(a) { decode.token(named: "circle", then: next, with: { use center <- custom_xy("center") use radius <- decode.token_wrapper(named: "radius", with: decode.float) decode.success(Circle(center:, radius:)) }) } pub type Arc { Arc(start: XY, mid: XY, end: XY) } pub fn arc(then next: NextFn(Arc, a)) -> Decoder(a) { decode.token(named: "arc", then: next, with: { use start <- custom_xy("start") use mid <- custom_xy("mid") use end <- custom_xy("end") decode.success(Arc(start:, mid:, end:)) }) } pub type Curve { Curve(points: Points) } pub fn curve(then next: NextFn(Curve, a)) -> Decoder(a) { decode.token(named: "bezier", then: next, with: { use points <- points() decode.success(Curve(points:)) }) } pub type PolyPoint { XYPolyPoint(XY) ArcPolyPoint(Arc) } pub fn poly_point(then next: NextFn(PolyPoint, a)) -> Decoder(a) { decode.one_of( xy |> decode.map(XYPolyPoint), or: [arc |> decode.map(ArcPolyPoint)], then: next, ) } pub type PolyPoints { PolyPoints(points: List(PolyPoint)) } pub fn poly_points(then next: NextFn(PolyPoints, a)) -> Decoder(a) { decode.token(named: "pts", then: next, with: { use points <- decode.list(poly_point) decode.success(PolyPoints(points:)) }) } pub type Points { Points(points: List(XY)) } pub fn points(then next: NextFn(Points, a)) -> Decoder(a) { decode.token(named: "pts", then: next, with: { use points <- decode.list(xy) decode.success(Points(points:)) }) } pub type StrokeType { DashStrokeType DashDotStrokeType DashDotDotStrokeType DotStrokeType DefaultStrokeType SolidStrokeType } pub fn stroke_type(then next: NextFn(StrokeType, a)) -> Decoder(a) { decode.token(named: "type", then: next, with: { use stroke_type <- decode.enum([ #("dash", DashStrokeType), #("dash_dot", DashDotStrokeType), #("dash_dot_dot", DashDotDotStrokeType), #("dot", DotStrokeType), #("default", DefaultStrokeType), #("solid", SolidStrokeType), ]) decode.success(stroke_type) }) } pub type Color { Color(r: Float, g: Float, b: Float, a: Float) } pub fn color(then next: NextFn(Color, a)) -> Decoder(a) { decode.token(named: "color", then: next, with: { use r <- decode.float() use g <- decode.float() use b <- decode.float() use a <- decode.float() decode.success(Color(r:, g:, b:, a:)) }) } pub type Stroke { Stroke(width: Float, type_: StrokeType, color: Option(Color)) } pub fn stroke(then next: NextFn(Stroke, a)) -> Decoder(a) { decode.token(named: "stroke", then: next, with: { use width <- width() use type_ <- stroke_type() use color <- decode.optional(color) decode.success(Stroke(width:, type_:, color:)) }) } pub type FillType { NoFill SolidFillType OutlineFillType BackgroundFillType } pub fn fill_type(then next: NextFn(FillType, a)) -> Decoder(a) { decode.enum( [ #("none", NoFill), #("solid", SolidFillType), #("outline", OutlineFillType), #("background", BackgroundFillType), ], then: next, ) } pub type Fill { Fill(type_: FillType) } pub fn fill(then next: NextFn(Fill, a)) -> Decoder(a) { decode.token(named: "fill", then: next, with: { use type_ <- decode.one_of( decode.token_wrapper(named: "type", with: fill_type, then: _), or: [fill_type], ) decode.success(Fill(type_:)) }) } pub type Size { Size(width: Float, height: Float) } pub fn size(then next: NextFn(Size, a)) -> Decoder(a) { decode.token(named: "size", then: next, with: { use width <- decode.float() use height <- decode.float() decode.success(Size(width:, height:)) }) } pub type Font { Font( face: Option(String), size: Size, thickness: Option(Float), bold: Option(Bool), italic: Option(Bool), line_spacing: Option(Float), ) } pub fn font(then next: NextFn(Font, a)) -> Decoder(a) { decode.token(named: "font", then: next, with: { use face <- decode.optional(decode.token_wrapper( named: "face", with: decode.string, then: _, )) use size <- size() use thickness <- decode.optional(thickness) use bold <- decode.optional(decode.one_of( decode.token_wrapper(named: "bold", with: yes_no, then: _), or: [decode.flag("bold", then: _)], then: _, )) use italic <- decode.optional(decode.one_of( decode.token_wrapper(named: "italic", with: yes_no, then: _), or: [decode.flag("italic", then: _)], then: _, )) use line_spacing <- decode.optional(decode.token_wrapper( named: "line_spacing", with: decode.float, then: _, )) decode.success(Font(face:, size:, thickness:, bold:, italic:, line_spacing:)) }) } pub type Horizontal { Left Right } pub fn horizontal(then next: NextFn(Horizontal, a)) -> Decoder(a) { decode.enum(then: next, with: [#("left", Left), #("right", Right)]) } pub type Vertical { Top Bottom } pub fn vertical(then next: NextFn(Vertical, a)) -> Decoder(a) { decode.enum(then: next, with: [#("top", Top), #("bottom", Bottom)]) } pub type Justify { Justify( horizontal: Option(Horizontal), vertical: Option(Vertical), mirror: Bool, ) } pub fn justify(then next: NextFn(Justify, a)) -> Decoder(a) { decode.token(named: "justify", then: next, with: { use horizontal <- decode.optional(horizontal) use vertical <- decode.optional(vertical) use mirror <- decode.flag("mirror") decode.success(Justify(horizontal:, vertical:, mirror:)) }) } pub type Effects { Effects(font: Font, justify: Option(Justify), hide: Option(Bool)) } pub fn effects(then next: NextFn(Effects, a)) -> Decoder(a) { decode.token(named: "effects", then: next, with: { use font <- font() use justify <- decode.optional(justify) use hide <- decode.optional(hide) decode.success(Effects(font:, justify:, hide:)) }) } pub type PaperSize { A0PaperSize A1PaperSize A2PaperSize A3PaperSize A4PaperSize A5PaperSize APaperSize BPaperSize CPaperSize DPaperSize EPaperSize CustomPaperSize(width: Float, height: Float) } pub fn paper_size(then next: NextFn(PaperSize, a)) -> Decoder(a) { decode.one_of( decode.enum(then: _, with: [ #("A0", A0PaperSize), #("A1", A1PaperSize), #("A2", A2PaperSize), #("A3", A3PaperSize), #("A4", A4PaperSize), #("A5", A5PaperSize), #("A", APaperSize), #("B", BPaperSize), #("C", CPaperSize), #("D", DPaperSize), #("E", EPaperSize), ]), or: [ decode.of(then: _, with: { use width <- decode.float() use height <- decode.float() decode.success(CustomPaperSize(width:, height:)) }), ], then: next, ) } pub type Paper { Paper(size: PaperSize, portrait: Bool) } pub fn paper(then next: NextFn(Paper, a)) -> Decoder(a) { decode.token(named: "paper", then: next, with: { use size <- paper_size() use portrait <- decode.flag("portrait") decode.success(Paper(size:, portrait:)) }) } pub type Comment { Comment(number: Int, comment: String) } pub fn comment(then next: NextFn(Comment, a)) -> Decoder(a) { decode.token(named: "comment", then: next, with: { use number <- decode.int() use comment <- decode.string() decode.success(Comment(number:, comment:)) }) } pub type TitleBlock { TitleBlock( title: String, date: String, revision: String, company: String, comment: Comment, ) } pub fn title_block(then next: NextFn(TitleBlock, a)) -> Decoder(a) { decode.token(named: "title_block", then: next, with: { use title <- decode.token_wrapper(named: "title", with: decode.string) use date <- decode.token_wrapper(named: "date", with: decode.string) use revision <- decode.token_wrapper(named: "rev", with: decode.string) use company <- decode.token_wrapper(named: "company", with: decode.string) use comment <- comment() decode.success(TitleBlock(title:, date:, revision:, company:, comment:)) }) } pub type Property { Property(key: String, value: String) } pub fn property(then next: NextFn(Property, a)) -> Decoder(a) { decode.token(named: "property", then: next, with: { use key <- decode.string() use value <- decode.string() decode.success(Property(key:, value:)) }) } pub type Uuid { Uuid(uuid: String) } pub fn uuid(then next: NextFn(Uuid, a)) -> Decoder(a) { decode.token(named: "uuid", then: next, with: { use uuid <- decode.string() decode.success(Uuid(uuid:)) }) } pub type Timestamp { Timestamp(ts: String) } pub fn timestamp(then next: NextFn(Timestamp, a)) -> Decoder(a) { decode.token(named: "tstamp", then: next, with: { use ts <- decode.string() decode.success(Timestamp(ts:)) }) } pub type Layer { Layer(layer: String) } pub fn layer(then next: NextFn(Layer, a)) -> Decoder(a) { decode.token(named: "layer", then: next, with: { use layer <- decode.name_string() decode.success(Layer(layer:)) }) } pub type Image { Image( position: PositionIdentifier, scale: Option(Float), layer: Option(Layer), uuid: Option(Uuid), data: String, ) } pub fn image(then next: NextFn(Image, a)) -> Decoder(a) { decode.token(named: "image", then: next, with: { use position <- position_identifier() use scale <- decode.optional(decode.token_wrapper( named: "scale", with: decode.float, then: _, )) use layer <- decode.optional(layer) use uuid <- decode.optional(uuid) use data <- decode.string() decode.success(Image(position:, scale:, layer:, uuid:, data:)) }) } pub type ConnectionType { NoConnection ThermalConnectionType SolidFillConnectionType } pub fn connection_type(then next: NextFn(ConnectionType, a)) -> Decoder(a) { decode.int_enum(then: next, with: [ NoConnection, ThermalConnectionType, SolidFillConnectionType, ]) } pub type FootprintProperty { FootprintProperty( key: String, value: String, position: PositionIdentifier, unlocked: Option(Bool), layer: Layer, hide: Option(Bool), uuid: Option(Uuid), effects: Effects, ) } pub fn footprint_property(then next: NextFn(FootprintProperty, a)) -> Decoder(a) { decode.token(named: "property", then: next, with: { use key <- decode.string() use value <- decode.string() use position <- position_identifier() use unlocked <- decode.optional(decode.token_wrapper( named: "unlocked", with: yes_no, then: _, )) use layer <- layer() use hide <- decode.optional(hide) use uuid <- decode.optional(uuid) use effects <- effects() decode.success(FootprintProperty( key:, value:, position:, unlocked:, layer:, hide:, uuid:, effects:, )) }) } pub type FootprintAttributeType { SmdAttributeType ThroughHoleAttributeType } pub fn footprint_attribute_type( then next: NextFn(FootprintAttributeType, a), ) -> Decoder(a) { decode.enum(then: next, with: [ #("smd", SmdAttributeType), #("through_hole", ThroughHoleAttributeType), ]) } pub type FootprintAttributes { FootprintAttributes( type_: Option(FootprintAttributeType), board_only: Bool, exclude_from_pos_files: Bool, exclude_from_bom: Bool, allow_soldermask_bridges: Bool, allow_missing_courtyard: Bool, ) } pub fn footprint_attributes( then next: NextFn(FootprintAttributes, a), ) -> Decoder(a) { decode.token(named: "attr", then: next, with: { use type_ <- decode.optional(footprint_attribute_type) use board_only <- decode.flag("board_only") use exclude_from_pos_files <- decode.flag("exclude_from_pos_files") use exclude_from_bom <- decode.flag("exclude_from_bom") use allow_soldermask_bridges <- decode.flag("allow_soldermask_bridges") use allow_missing_courtyard <- decode.flag("allow_missing_courtyard") decode.success(FootprintAttributes( type_:, board_only:, exclude_from_pos_files:, exclude_from_bom:, allow_soldermask_bridges:, allow_missing_courtyard:, )) }) } pub type FootprintTextType { ReferenceTextType ValueTextType UserTextType } pub fn footprint_text_type( then next: NextFn(FootprintTextType, a), ) -> Decoder(a) { decode.enum(then: next, with: [ #("reference", ReferenceTextType), #("value", ValueTextType), #("user", UserTextType), ]) } pub type FootprintText { FootprintText( type_: FootprintTextType, text: String, position: PositionIdentifier, unlocked: Option(Bool), layer: Layer, hide: Option(Bool), uuid: Option(Uuid), effects: Effects, timestamp: Option(Timestamp), ) } pub fn footprint_text(then next: NextFn(FootprintText, a)) -> Decoder(a) { decode.token(named: "fp_text", then: next, with: { use type_ <- footprint_text_type() use text <- decode.name_string() use position <- position_identifier() use unlocked <- decode.optional(decode.token_wrapper( named: "unlocked", with: yes_no, then: _, )) use layer <- layer() use hide <- decode.optional(hide) use uuid <- decode.optional(uuid) use effects <- effects() use timestamp <- decode.optional(timestamp) decode.success(FootprintText( type_:, text:, position:, unlocked:, layer:, hide:, uuid:, effects:, timestamp:, )) }) } pub type FootprintTextBox { FootprintTextBox( locked: Bool, text: String, start: Option(XY), end: Option(XY), corners: Option(#(XY, XY, XY, XY)), margins: Option(#(Float, Float, Float, Float)), angle: Option(Float), layer: Layer, uuid: Option(Uuid), effects: Effects, border: Option(Bool), stroke: Option(Stroke), render_cache: Option(Nil), timestamp: Option(Timestamp), ) } pub fn footprint_text_box(then next: NextFn(FootprintTextBox, a)) -> Decoder(a) { decode.token(named: "fp_text_box", then: next, with: { use locked <- decode.flag("locked") use text <- decode.string() use start <- decode.optional(custom_xy("start", then: _)) use end <- decode.optional(custom_xy("end", then: _)) use corners <- decode.optional(corners) use margins <- decode.optional(margins) use angle <- decode.optional(angle) use layer <- layer() use uuid <- decode.optional(uuid) use effects <- effects() use border <- decode.optional(decode.token_wrapper( named: "border", with: yes_no, then: _, )) use stroke <- decode.optional(stroke) let render_cache = None use timestamp <- decode.optional(timestamp) decode.success(FootprintTextBox( locked:, text:, start:, end:, corners:, margins:, angle:, layer:, uuid:, effects:, border:, stroke:, render_cache:, timestamp:, )) }) } pub type FootprintLine { FootprintLine( start: XY, end: XY, stroke: Option(Stroke), layer: Layer, width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_line(then next: NextFn(FootprintLine, a)) -> Decoder(a) { decode.token(named: "fp_line", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") use stroke <- decode.optional(stroke) use layer <- layer() use width <- decode.optional(width) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintLine( start:, end:, stroke:, layer:, width:, locked:, uuid:, timestamp:, )) }) } pub type FootprintRectangle { FootprintRectangle( start: XY, end: XY, stroke: Option(Stroke), filled: Option(Bool), layer: Layer, fill: Option(Fill), width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_rectangle( then next: NextFn(FootprintRectangle, a), ) -> Decoder(a) { decode.token(named: "fp_rect", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") use stroke <- decode.optional(stroke) use filled <- decode.optional(filled) use layer <- layer() use fill_a <- decode.optional(fill) use width <- decode.optional(width) use fill_b <- decode.optional(fill) let fill = fill_a |> option.or(fill_b) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintRectangle( start:, end:, stroke:, filled:, layer:, fill:, width:, locked:, uuid:, timestamp:, )) }) } pub type FootprintCircle { FootprintCircle( center: XY, end: XY, stroke: Option(Stroke), filled: Option(Bool), layer: Layer, fill: Option(Fill), width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_circle(then next: NextFn(FootprintCircle, a)) -> Decoder(a) { decode.token(named: "fp_circle", then: next, with: { use center <- custom_xy("center") use end <- custom_xy("end") use stroke <- decode.optional(stroke) use filled <- decode.optional(filled) use layer <- layer() use fill_a <- decode.optional(fill) use width <- decode.optional(width) use fill_b <- decode.optional(fill) let fill = fill_a |> option.or(fill_b) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintCircle( center:, end:, stroke:, filled:, layer:, fill:, width:, locked:, uuid:, timestamp:, )) }) } pub type FootprintArc { FootprintArc( start: XY, mid: XY, end: XY, stroke: Option(Stroke), layer: Layer, width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_arc(then next: NextFn(FootprintArc, a)) -> Decoder(a) { decode.token(named: "fp_arc", then: next, with: { use start <- custom_xy("start") use mid <- custom_xy("mid") use end <- custom_xy("end") use stroke <- decode.optional(stroke) use layer <- layer() use width <- decode.optional(width) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintArc( start:, mid:, end:, stroke:, layer:, width:, locked:, uuid:, timestamp:, )) }) } pub type FootprintPolygon { FootprintPolygon( points: PolyPoints, stroke: Option(Stroke), filled: Option(Bool), layer: Layer, fill: Option(Fill), width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_polygon(then next: NextFn(FootprintPolygon, a)) -> Decoder(a) { decode.token(named: "fp_poly", then: next, with: { use points <- poly_points() use stroke <- decode.optional(stroke) use filled <- decode.optional(filled) use layer <- layer() use fill_a <- decode.optional(fill) use width <- decode.optional(width) use fill_b <- decode.optional(fill) let fill = fill_a |> option.or(fill_b) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintPolygon( points:, stroke:, filled:, layer:, fill:, width:, locked:, uuid:, timestamp:, )) }) } pub type FootprintCurve { FootprintCurve( points: Points, stroke: Option(Stroke), layer: Layer, width: Option(Float), locked: Bool, uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn footprint_curve(then next: NextFn(FootprintCurve, a)) -> Decoder(a) { decode.token(named: "fp_curve", then: next, with: { use points <- points() use stroke <- decode.optional(stroke) use layer <- layer() use width <- decode.optional(width) use locked <- decode.flag("locked") use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(FootprintCurve( points:, stroke:, layer:, width:, locked:, uuid:, timestamp:, )) }) } pub type DimensionType { AlignedDimensionType LeaderDimensionType CenterDimensionType OrthogonalDimensionType RadialDimensionType } pub fn dimension_type(then next: NextFn(DimensionType, a)) -> Decoder(a) { decode.enum( with: [ #("aligned", AlignedDimensionType), #("leader", LeaderDimensionType), #("center", CenterDimensionType), #("orthogonal", OrthogonalDimensionType), #("radial", RadialDimensionType), ], then: next, ) } pub type Unit { InchesUnit MilsUnit MillimetersUnit AutomaticUnit } pub fn unit(then next: NextFn(Unit, a)) -> Decoder(a) { decode.int_enum( with: [InchesUnit, MilsUnit, MillimetersUnit, AutomaticUnit], then: next, ) } pub type UnitFormat { NoSuffixUnitFormat BareSuffixUnitFormat WrapSuffixUnitFormat } pub fn unit_format(then next: NextFn(UnitFormat, a)) -> Decoder(a) { decode.int_enum( with: [NoSuffixUnitFormat, BareSuffixUnitFormat, WrapSuffixUnitFormat], then: next, ) } pub type DimensionFormat { DimensionFormat( prefix: Option(String), suffix: Option(String), unit: Unit, unit_format: UnitFormat, precision: Int, override_value: Option(String), suppress_zeros: Option(Bool), ) } pub fn dimension_format(then next: NextFn(DimensionFormat, a)) -> Decoder(a) { decode.token(named: "format", then: next, with: { use prefix <- decode.optional(decode.token_wrapper( named: "prefix", with: decode.string, then: _, )) use suffix <- decode.optional(decode.token_wrapper( named: "suffix", with: decode.string, then: _, )) use unit <- decode.token_wrapper(named: "units", with: unit) use unit_format <- decode.token_wrapper( named: "units_format", with: unit_format, ) use precision <- decode.token_wrapper(named: "precision", with: decode.int) use override_value <- decode.optional(decode.token_wrapper( named: "override_value", with: decode.string, then: _, )) use suppress_zeros <- decode.optional(decode.token_wrapper( named: "suppress_zeros", with: yes_no, then: _, )) decode.success(DimensionFormat( prefix:, suffix:, unit:, unit_format:, precision:, override_value:, suppress_zeros:, )) }) } pub type TextPositionMode { OutsideTextPositionMode InlineTextPositionMode ManualTextPositionMode } pub fn text_position_mode(then next: NextFn(TextPositionMode, a)) -> Decoder(a) { decode.int_enum( with: [ OutsideTextPositionMode, InlineTextPositionMode, ManualTextPositionMode, ], then: next, ) } pub type ArrowDirection { OutwardArrowDirection InwardArrowDirection } pub fn arrow_direction(then next: NextFn(ArrowDirection, a)) -> Decoder(a) { decode.enum( with: [ #("outward", OutwardArrowDirection), #("inward", InwardArrowDirection), ], then: next, ) } pub type TextFrameType { NoFrame RectangleFrameType CircleFrameType RoundedRectangleFrameType } pub fn text_frame_type(then next: NextFn(TextFrameType, a)) -> Decoder(a) { decode.int_enum( with: [ NoFrame, RectangleFrameType, CircleFrameType, RoundedRectangleFrameType, ], then: next, ) } pub type DimensionStyle { DimensionStyle( thickness: Float, arrow_length: Float, text_position_mode: TextPositionMode, arrow_direction: Option(ArrowDirection), extension_height: Option(Float), text_frame_type: Option(TextFrameType), extension_offset: Option(Float), keep_text_aligned: Option(Bool), ) } pub fn dimension_style(then next: NextFn(DimensionStyle, a)) -> Decoder(a) { decode.token(named: "style", then: next, with: { use thickness <- thickness() use arrow_length <- decode.token_wrapper( named: "arrow_length", with: decode.float, ) use text_position_mode <- decode.token_wrapper( named: "text_position_mode", with: text_position_mode, ) use arrow_direction <- decode.optional(decode.token_wrapper( named: "arrow_direction", with: arrow_direction, then: _, )) use extension_height <- decode.optional(decode.token_wrapper( named: "extension_height", with: decode.float, then: _, )) use text_frame_type <- decode.optional(decode.token_wrapper( named: "text_frame", with: text_frame_type, then: _, )) use extension_offset <- decode.optional(decode.token_wrapper( named: "extension_offset", with: decode.float, then: _, )) use keep_text_aligned <- decode.optional(decode.token_wrapper( named: "keep_text_aligned", with: yes_no, then: _, )) decode.success(DimensionStyle( thickness:, arrow_length:, text_position_mode:, arrow_direction:, extension_height:, text_frame_type:, extension_offset:, keep_text_aligned:, )) }) } pub type Dimension { Dimension( locked: Bool, type_: DimensionType, layer: Layer, uuid: Option(Uuid), start: XY, end: XY, height: Option(Float), orientation: Option(Float), leader_length: Option(Float), format: Option(DimensionFormat), style: DimensionStyle, text: Option(GraphicalText), ) } pub fn dimension(then next: NextFn(Dimension, a)) -> Decoder(a) { decode.token(named: "dimension", then: next, with: { use locked <- decode.flag("locked") use type_ <- decode.token_wrapper(named: "type", with: dimension_type) use layer <- layer() use uuid <- decode.optional(uuid) use #(start, end) <- decode.token(named: "pts", with: { use xy1 <- xy() use xy2 <- xy() decode.success(#(xy1, xy2)) }) use height <- decode.optional(decode.token_wrapper( named: "height", with: decode.float, then: _, )) use orientation <- decode.optional(decode.token_wrapper( named: "orientation", with: decode.float, then: _, )) use leader_length <- decode.optional(decode.token_wrapper( named: "leader_length", with: decode.float, then: _, )) use format <- decode.optional(dimension_format) use style <- dimension_style() use text <- decode.optional(graphical_text) decode.success(Dimension( locked:, type_:, layer:, uuid:, start:, end:, height:, orientation:, leader_length:, format:, style:, text:, )) }) } pub type FootprintGraphicItem { TextFootprintGraphicItem(FootprintText) TextBoxFootprintGraphicItem(FootprintTextBox) LineFootprintGraphicItem(FootprintLine) RectangleFootprintGraphicItem(FootprintRectangle) CircleFootprintGraphicItem(FootprintCircle) ArcFootprintGraphicItem(FootprintArc) PolygonFootprintGraphicItem(FootprintPolygon) CurveFootprintGraphicItem(FootprintCurve) DimensionFootprintGraphicItem(Dimension) } pub fn footprint_graphic_item( then next: NextFn(FootprintGraphicItem, a), ) -> Decoder(a) { decode.one_of( footprint_text |> decode.map(TextFootprintGraphicItem), or: [ footprint_text_box |> decode.map(TextBoxFootprintGraphicItem), footprint_line |> decode.map(LineFootprintGraphicItem), footprint_rectangle |> decode.map(RectangleFootprintGraphicItem), footprint_circle |> decode.map(CircleFootprintGraphicItem), footprint_arc |> decode.map(ArcFootprintGraphicItem), footprint_polygon |> decode.map(PolygonFootprintGraphicItem), footprint_curve |> decode.map(CurveFootprintGraphicItem), dimension |> decode.map(DimensionFootprintGraphicItem), ], then: next, ) } pub type GraphicalTextLayer { GraphicalTextLayer(layer: String, knockout: Bool) } pub fn graphical_text_layer( then next: NextFn(GraphicalTextLayer, a), ) -> Decoder(a) { decode.token(named: "layer", then: next, with: { use layer <- decode.string() use knockout <- decode.flag("knockout") decode.success(GraphicalTextLayer(layer:, knockout:)) }) } pub type GraphicalText { GraphicalText( text: String, position: PositionIdentifier, layer: Option(GraphicalTextLayer), uuid: Option(Uuid), effects: Effects, ) } pub fn graphical_text(then next: NextFn(GraphicalText, a)) -> Decoder(a) { decode.token(named: "gr_text", then: next, with: { use text <- decode.string() use position <- position_identifier() use layer <- decode.optional(graphical_text_layer) use uuid <- decode.optional(uuid) use effects <- effects() decode.success(GraphicalText(text:, position:, layer:, uuid:, effects:)) }) } pub type GraphicalTextBox { GraphicalTextBox( locked: Bool, text: String, start: Option(XY), end: Option(XY), corners: Option(#(XY, XY, XY, XY)), angle: Option(Float), layer: Option(Layer), uuid: Option(Uuid), effects: Effects, stroke: Option(Stroke), render_cache: Option(Nil), ) } pub fn graphical_text_box(then next: NextFn(GraphicalTextBox, a)) -> Decoder(a) { decode.token(named: "gr_text_box", then: next, with: { use locked <- decode.flag("locked") use text <- decode.string() use start <- decode.optional(custom_xy("start", then: _)) use end <- decode.optional(custom_xy("end", then: _)) use corners <- decode.optional(corners) use angle <- decode.optional(angle) use layer <- decode.optional(layer) use uuid <- decode.optional(uuid) use effects <- effects() use stroke <- decode.optional(stroke) let render_cache = None decode.success(GraphicalTextBox( locked:, text:, start:, end:, corners:, angle:, layer:, uuid:, effects:, stroke:, render_cache:, )) }) } pub type GraphicalLine { GraphicalLine( start: XY, end: XY, angle: Option(Float), layer: Option(Layer), width: Float, uuid: Option(Uuid), ) } pub fn graphical_line(then next: NextFn(GraphicalLine, a)) -> Decoder(a) { decode.token(named: "gr_line", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") use angle <- decode.optional(angle) use layer <- decode.optional(layer) use width <- width() use uuid <- decode.optional(uuid) decode.success(GraphicalLine(start:, end:, angle:, layer:, width:, uuid:)) }) } pub type GraphicalRectangle { GraphicalRectangle( start: XY, end: XY, layer: Option(Layer), width: Float, fill: Option(Bool), uuid: Option(Uuid), ) } pub fn graphical_rectangle( then next: NextFn(GraphicalRectangle, a), ) -> Decoder(a) { decode.token(named: "gr_rect", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") use layer <- decode.optional(layer) use width <- width() use fill <- decode.optional(filled) use uuid <- decode.optional(uuid) decode.success(GraphicalRectangle( start:, end:, layer:, width:, fill:, uuid:, )) }) } pub type GraphicalCircle { GraphicalCircle( center: XY, end: XY, layer: Option(Layer), width: Float, fill: Option(Bool), uuid: Option(Uuid), ) } pub fn graphical_circle(then next: NextFn(GraphicalCircle, a)) -> Decoder(a) { decode.token(named: "gr_circle", then: next, with: { use center <- custom_xy("center") use end <- custom_xy("end") use layer <- decode.optional(layer) use width <- width() use fill <- decode.optional(filled) use uuid <- decode.optional(uuid) decode.success(GraphicalCircle(center:, end:, layer:, width:, fill:, uuid:)) }) } pub type GraphicalArc { GraphicalArc( start: XY, mid: XY, end: XY, layer: Option(Layer), width: Float, uuid: Option(Uuid), ) } pub fn graphical_arc(then next: NextFn(GraphicalArc, a)) -> Decoder(a) { decode.token(named: "gr_arc", then: next, with: { use start <- custom_xy("start") use mid <- custom_xy("mid") use end <- custom_xy("end") use layer <- decode.optional(layer) use width <- width() use uuid <- decode.optional(uuid) decode.success(GraphicalArc(start:, mid:, end:, layer:, width:, uuid:)) }) } pub type GraphicalPolygon { GraphicalPolygon( points: PolyPoints, layer: Option(Layer), width: Float, fill: Option(Bool), uuid: Option(Uuid), ) } pub fn graphical_polygon(then next: NextFn(GraphicalPolygon, a)) -> Decoder(a) { decode.token(named: "gr_poly", then: next, with: { use points <- poly_points() use layer <- decode.optional(layer) use width <- width() use fill <- decode.optional(filled) use uuid <- decode.optional(uuid) decode.success(GraphicalPolygon(points:, layer:, width:, fill:, uuid:)) }) } pub type GraphicalCurve { GraphicalCurve( points: Points, layer: Option(Layer), width: Float, uuid: Option(Uuid), ) } pub fn graphical_curve(then next: NextFn(GraphicalCurve, a)) -> Decoder(a) { decode.token(named: "bezier", then: next, with: { use points <- points() use layer <- decode.optional(layer) use width <- width() use uuid <- decode.optional(uuid) decode.success(GraphicalCurve(points:, layer:, width:, uuid:)) }) } pub type GraphicalBoundingBox { GraphicalBoundingBox(start: XY, end: XY) } pub fn graphical_bounding_box( then next: NextFn(GraphicalBoundingBox, a), ) -> Decoder(a) { decode.token(named: "gr_bbox", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") decode.success(GraphicalBoundingBox(start:, end:)) }) } pub type GraphicItem { TextGraphicItem(GraphicalText) TextBoxGraphicItem(GraphicalTextBox) LineGraphicItem(GraphicalLine) RectangleGraphicItem(GraphicalRectangle) CircleGraphicItem(GraphicalCircle) ArcGraphicItem(GraphicalArc) PolygonGraphicItem(GraphicalPolygon) CurveGraphicItem(GraphicalCurve) DimensionGraphicItem(Dimension) BoundingBoxGraphicItem(GraphicalBoundingBox) } pub fn graphic_item(then next: NextFn(GraphicItem, a)) -> Decoder(a) { decode.one_of( graphical_text |> decode.map(TextGraphicItem), or: [ graphical_text_box |> decode.map(TextBoxGraphicItem), graphical_line |> decode.map(LineGraphicItem), graphical_rectangle |> decode.map(RectangleGraphicItem), graphical_circle |> decode.map(CircleGraphicItem), graphical_arc |> decode.map(ArcGraphicItem), graphical_polygon |> decode.map(PolygonGraphicItem), graphical_curve |> decode.map(CurveGraphicItem), dimension |> decode.map(DimensionGraphicItem), graphical_bounding_box |> decode.map(BoundingBoxGraphicItem), ], then: next, ) } pub type SymbolText { SymbolText(text: String, position: PositionIdentifier, effects: Effects) } pub fn symbol_text(then next: NextFn(SymbolText, a)) -> Decoder(a) { decode.token(named: "text", then: next, with: { use text <- decode.string() use position <- position_identifier() use effects <- effects() decode.success(SymbolText(text:, position:, effects:)) }) } pub type SymbolTextBox { SymbolTextBox( text: String, position: PositionIdentifier, size: Size, margins: Option(#(Float, Float, Float, Float)), stroke: Stroke, fill: Fill, effects: Effects, ) } pub fn symbol_text_box(then next: NextFn(SymbolTextBox, a)) -> Decoder(a) { decode.token(named: "text_box", then: next, with: { use text <- decode.string() use position <- position_identifier() use size <- size() use margins <- decode.optional(margins) use stroke <- stroke() use fill <- fill() use effects <- effects() decode.success(SymbolTextBox( text:, position:, size:, margins:, stroke:, fill:, effects:, )) }) } pub type SymbolLine { SymbolLine(points: Points, stroke: Stroke, fill: Fill) } pub fn symbol_line(then next: NextFn(SymbolLine, a)) -> Decoder(a) { decode.token(named: "polyline", then: next, with: { use points <- points() use stroke <- stroke() use fill <- fill() decode.success(SymbolLine(points:, stroke:, fill:)) }) } pub type SymbolRectangle { SymbolRectangle(start: XY, end: XY, stroke: Stroke, fill: Fill) } pub fn symbol_rectangle(then next: NextFn(SymbolRectangle, a)) -> Decoder(a) { decode.token(named: "rectangle", then: next, with: { use start <- custom_xy("start") use end <- custom_xy("end") use stroke <- stroke() use fill <- fill() decode.success(SymbolRectangle(start:, end:, stroke:, fill:)) }) } pub type SymbolCircle { SymbolCircle(center: XY, radius: Float, stroke: Stroke, fill: Fill) } pub fn symbol_circle(then next: NextFn(SymbolCircle, a)) -> Decoder(a) { decode.token(named: "circle", then: next, with: { use center <- custom_xy("center") use radius <- decode.token_wrapper(named: "radius", with: decode.float) use stroke <- stroke() use fill <- fill() decode.success(SymbolCircle(center:, radius:, stroke:, fill:)) }) } pub type SymbolArc { SymbolArc(start: XY, mid: XY, end: XY, stroke: Stroke, fill: Fill) } pub fn symbol_arc(then next: NextFn(SymbolArc, a)) -> Decoder(a) { decode.token(named: "arc", then: next, with: { use start <- custom_xy("start") use mid <- custom_xy("mid") use end <- custom_xy("end") use stroke <- stroke() use fill <- fill() decode.success(SymbolArc(start:, mid:, end:, stroke:, fill:)) }) } pub type SymbolCurve { SymbolCurve(points: Points, stroke: Stroke, fill: Fill) } pub fn symbol_curve(then next: NextFn(SymbolCurve, a)) -> Decoder(a) { decode.token(named: "bezier", then: next, with: { use points <- points() use stroke <- stroke() use fill <- fill() decode.success(SymbolCurve(points:, stroke:, fill:)) }) } pub type PinElectricalType { InputElectricalType OutputElectricalType BidirectionalElectricalType TriStateElectricalType PassiveElectricalType FreeElectricalType UnspecifiedElectricalType PowerInElectricalType PowerOutElectricalType OpenCollectorElectricalType OpenEmitterElectricalType NoConnectElectricalType } pub fn pin_electrical_type( then next: NextFn(PinElectricalType, a), ) -> Decoder(a) { decode.enum( with: [ #("input", InputElectricalType), #("output", OutputElectricalType), #("bidirectional", BidirectionalElectricalType), #("tri_state", TriStateElectricalType), #("passive", PassiveElectricalType), #("free", FreeElectricalType), #("unspecified", UnspecifiedElectricalType), #("power_in", PowerInElectricalType), #("power_out", PowerOutElectricalType), #("open_collector", OpenCollectorElectricalType), #("open_emitter", OpenEmitterElectricalType), #("no_connect", NoConnectElectricalType), ], then: next, ) } pub type PinGraphicalStyle { LineGraphicalStyle InvertedGraphicalStyle ClockGraphicalStyle InvertedClockGraphicalStyle InputLowGraphicalStyle ClockLowGraphicalStyle OutputLowGraphicalStyle EdgeClockHighGraphicalStyle NonLogicGraphicalStyle } pub fn pin_graphical_style( then next: NextFn(PinGraphicalStyle, a), ) -> Decoder(a) { decode.enum( with: [ #("line", LineGraphicalStyle), #("inverted", InvertedGraphicalStyle), #("clock", ClockGraphicalStyle), #("inverted_clock", InvertedClockGraphicalStyle), #("input_low", InputLowGraphicalStyle), #("clock_low", ClockLowGraphicalStyle), #("output_low", OutputLowGraphicalStyle), #("edge_clock_high", EdgeClockHighGraphicalStyle), #("non_logic", NonLogicGraphicalStyle), ], then: next, ) } pub type PinName { PinName(name: String, effects: Effects) } pub fn pin_name(then next: NextFn(PinName, a)) -> Decoder(a) { decode.token(named: "name", then: next, with: { use name <- decode.string() use effects <- effects() decode.success(PinName(name:, effects:)) }) } pub type PinNumber { PinNumber(number: String, effects: Effects) } pub fn pin_number(then next: NextFn(PinNumber, a)) -> Decoder(a) { decode.token(named: "number", then: next, with: { use number <- decode.string() use effects <- effects() decode.success(PinNumber(number:, effects:)) }) } pub type PinAlternate { PinAlternate( name: String, electrical_type: PinElectricalType, graphical_style: PinGraphicalStyle, ) } pub fn pin_alternate(then next: NextFn(PinAlternate, a)) -> Decoder(a) { decode.token(named: "alternate", then: next, with: { use name <- decode.string() use electrical_type <- pin_electrical_type() use graphical_style <- pin_graphical_style() decode.success(PinAlternate(name:, electrical_type:, graphical_style:)) }) } pub type SymbolPin { SymbolPin( electrical_type: PinElectricalType, graphical_style: PinGraphicalStyle, position: PositionIdentifier, length: Float, hide: Option(Bool), name: PinName, number: PinNumber, alternatives: List(PinAlternate), ) } pub fn symbol_pin(then next: NextFn(SymbolPin, a)) -> Decoder(a) { decode.token(named: "pin", then: next, with: { use electrical_type <- pin_electrical_type() use graphical_style <- pin_graphical_style() use position <- position_identifier() use length <- decode.token_wrapper(named: "length", with: decode.float) use hide <- decode.optional(hide) use name <- pin_name() use number <- pin_number() use alternatives <- decode.list(pin_alternate) decode.success(SymbolPin( electrical_type:, graphical_style:, position:, length:, hide:, name:, number:, alternatives:, )) }) } pub type SymbolGraphicItem { TextSymbolGraphicItem(SymbolText) TextBoxSymbolGraphicItem(SymbolTextBox) LineSymbolGraphicItem(SymbolLine) RectangleSymbolGraphicItem(SymbolRectangle) CircleSymbolGraphicItem(SymbolCircle) ArcSymbolGraphicItem(SymbolArc) CurveSymbolGraphicItem(SymbolCurve) } pub fn symbol_graphic_item( then next: NextFn(SymbolGraphicItem, a), ) -> Decoder(a) { decode.one_of( symbol_text |> decode.map(TextSymbolGraphicItem), or: [ symbol_text_box |> decode.map(TextBoxSymbolGraphicItem), symbol_line |> decode.map(LineSymbolGraphicItem), symbol_rectangle |> decode.map(RectangleSymbolGraphicItem), symbol_circle |> decode.map(CircleSymbolGraphicItem), symbol_arc |> decode.map(ArcSymbolGraphicItem), symbol_curve |> decode.map(CurveSymbolGraphicItem), ], then: next, ) } pub type PadType { ThroughHolePadType SmdPadPadType ConnectPadType NpThroughHolePadType } pub fn pad_type(then next: NextFn(PadType, a)) -> Decoder(a) { decode.enum( with: [ #("thru_hole", ThroughHolePadType), #("smd", SmdPadPadType), #("connect", ConnectPadType), #("np_thru_hole", NpThroughHolePadType), ], then: next, ) } pub type PadShape { CirclePadShape RectanglePadShape OvalPadShape TrapezoidPadShape RoundRectPadShape CustomPadShape } pub fn pad_shape(then next: NextFn(PadShape, a)) -> Decoder(a) { decode.enum( with: [ #("circle", CirclePadShape), #("rect", RectanglePadShape), #("oval", OvalPadShape), #("roundrect", RoundRectPadShape), #("trapezoid", TrapezoidPadShape), #("custom", CustomPadShape), ], then: next, ) } pub type PadDrillDefinition { PadDrillDefinition( oval: Bool, diameter: Option(Float), width: Option(Float), offset: Option(XY), ) } pub fn pad_drill_definition( then next: NextFn(PadDrillDefinition, a), ) -> Decoder(a) { decode.token(named: "drill", then: next, with: { use oval <- decode.flag("oval") use diameter <- decode.optional(decode.float) use width <- decode.optional(decode.float) use offset <- decode.optional(custom_xy("offset", then: _)) decode.success(PadDrillDefinition(oval:, diameter:, width:, offset:)) }) } pub type PadProperty { BgaPadProperty FiducialGlobPadProperty FiducialLocPadProperty TestpointPadProperty HeatsinkPadProperty CastellatedPadProperty } pub fn pad_property(then next: NextFn(PadProperty, a)) -> Decoder(a) { decode.enum( with: [ #("pad_prop_bga", BgaPadProperty), #("pad_prop_fiducial_glob", FiducialGlobPadProperty), #("pad_prop_fiducial_loc", FiducialLocPadProperty), #("pad_prop_testpoint", TestpointPadProperty), #("pad_prop_heatsink", HeatsinkPadProperty), #("pad_prop_castellated", CastellatedPadProperty), ], then: next, ) } pub type Corner { TopLeft TopRight BottomLeft BottomRight } pub fn corner(then next: NextFn(Corner, a)) -> Decoder(a) { decode.enum( with: [ #("top_left", TopLeft), #("top_right", TopRight), #("bottom_left", BottomLeft), #("bottom_right", BottomRight), ], then: next, ) } pub type Net { Net(number: Int, name: String) } pub fn net(then next: NextFn(Net, a)) -> Decoder(a) { decode.token(named: "net", then: next, with: { use number <- decode.int() use name <- decode.string() decode.success(Net(number:, name:)) }) } pub type ClearanceType { OutlineClearanceType ConvexHullClearanceType } pub fn clearance_type(then next: NextFn(ClearanceType, a)) -> Decoder(a) { decode.enum( with: [ #("outline", OutlineClearanceType), #("convexhull", ConvexHullClearanceType), ], then: next, ) } pub type AnchorPadShape { RectangleAnchorPadShape CircleAnchorPadShape } pub fn anchor_pad_shape(then next: NextFn(AnchorPadShape, a)) -> Decoder(a) { decode.enum( with: [ #("rect", RectangleAnchorPadShape), #("circle", CircleAnchorPadShape), ], then: next, ) } pub type CustomPadOptions { CustomPadOptions(clearance: ClearanceType, anchor: AnchorPadShape) } pub fn custom_pad_options(then next: NextFn(CustomPadOptions, a)) -> Decoder(a) { decode.token(named: "options", then: next, with: { use clearance <- decode.token_wrapper( named: "clearance", with: clearance_type, ) use anchor <- decode.token_wrapper(named: "anchor", with: anchor_pad_shape) decode.success(CustomPadOptions(clearance:, anchor:)) }) } pub type CustomPadPrimitives { CustomPadPrimitives( graphic_items: List(GraphicItem), width: Option(Float), fill: Option(Bool), ) } pub fn custom_pad_primitives( then next: NextFn(CustomPadPrimitives, a), ) -> Decoder(a) { decode.token(named: "primitives", then: next, with: { use graphic_items <- decode.list(graphic_item) use width <- decode.optional(width) use fill <- decode.optional(filled) decode.success(CustomPadPrimitives(graphic_items:, width:, fill:)) }) } pub type Pad { Pad( number: String, type_: PadType, shape: PadShape, position: PositionIdentifier, locked: Bool, size: Size, drill: Option(PadDrillDefinition), rect_delta: Option(XY), property: Option(PadProperty), layers: List(Layer), remove_unused_layers: Option(Bool), keep_end_layers: Option(Bool), roundrect_rratio: Option(Float), chamfer_ratio: Option(Float), chamfer: Option(List(Corner)), net: Option(Net), pin_function: Option(String), pin_type: Option(String), die_length: Option(Float), solder_mask_margin: Option(Float), solder_paste_margin: Option(Float), solder_paste_margin_ratio: Option(Float), clearance: Option(Float), zone_connection: Option(ConnectionType), thermal_width: Option(Float), thermal_gap: Option(Float), thermal_bridge_width: Option(Float), thermal_bridge_angle: Option(Float), custom_options: Option(CustomPadOptions), custom_primitives: Option(CustomPadPrimitives), uuid: Option(Uuid), timestamp: Option(Timestamp), ) } pub fn pad(then next: NextFn(Pad, a)) -> Decoder(a) { decode.token(named: "pad", then: next, with: { use number <- decode.name_number_string() use type_ <- pad_type() use shape <- pad_shape() use position <- position_identifier() use locked <- decode.flag("locked") use size <- size() use drill <- decode.optional(pad_drill_definition) use rect_delta <- decode.optional(custom_xy(named: "rect_delta", then: _)) use property <- decode.optional(decode.token_wrapper( named: "property", with: pad_property, then: _, )) use layers <- layers() use remove_unused_layers <- decode.optional(decode.token_wrapper( named: "remove_unused_layers", with: decode.optional(yes_no, then: _), then: _, )) let remove_unused_layers = option.flatten(remove_unused_layers) use keep_end_layers <- decode.optional(decode.token_wrapper( named: "keep_end_layers", with: decode.optional(yes_no, then: _), then: _, )) let keep_end_layers = option.flatten(keep_end_layers) use roundrect_rratio <- decode.optional(decode.token_wrapper( named: "roundrect_rratio", with: decode.float, then: _, )) use chamfer_ratio <- decode.optional(decode.token_wrapper( named: "chamfer_ratio", with: decode.float, then: _, )) use chamfer <- decode.optional(decode.token_wrapper( named: "chamfer", with: decode.list(corner, then: _), then: _, )) use net <- decode.optional(net) use pin_function <- decode.optional(decode.token_wrapper( named: "pinfunction", with: decode.string, then: _, )) use pin_type <- decode.optional(decode.token_wrapper( named: "pintype", with: decode.string, then: _, )) use die_length <- decode.optional(decode.token_wrapper( named: "die_length", with: decode.float, then: _, )) use solder_mask_margin <- decode.optional(decode.token_wrapper( named: "solder_mask_margin", with: decode.float, then: _, )) use solder_paste_margin <- decode.optional(decode.token_wrapper( named: "solder_paste_margin", with: decode.float, then: _, )) use solder_paste_margin_ratio <- decode.optional(decode.token_wrapper( named: "solder_paste_margin_ratio", with: decode.float, then: _, )) use clearance <- decode.optional(decode.token_wrapper( named: "clearance", with: decode.float, then: _, )) use zone_connection <- decode.optional(decode.token_wrapper( named: "zone_connect", with: connection_type, then: _, )) use thermal_width <- decode.optional(decode.token_wrapper( named: "thermal_width", with: decode.float, then: _, )) use thermal_gap <- decode.optional(decode.token_wrapper( named: "thermal_gap", with: decode.float, then: _, )) use thermal_bridge_width <- decode.optional(decode.token_wrapper( named: "thermal_bridge_width", with: decode.float, then: _, )) use thermal_bridge_angle <- decode.optional(decode.token_wrapper( named: "thermal_bridge_angle", with: decode.float, then: _, )) use custom_options <- decode.optional(custom_pad_options) use custom_primitives <- decode.optional(custom_pad_primitives) use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) decode.success(Pad( number:, type_:, shape:, position:, locked:, size:, drill:, rect_delta:, property:, layers:, remove_unused_layers:, keep_end_layers:, roundrect_rratio:, chamfer_ratio:, chamfer:, net:, pin_function:, pin_type:, die_length:, solder_mask_margin:, solder_paste_margin:, solder_paste_margin_ratio:, clearance:, zone_connection:, thermal_width:, thermal_gap:, thermal_bridge_width:, thermal_bridge_angle:, custom_options:, custom_primitives:, uuid:, timestamp:, )) }) } pub type HatchStyle { NoHatch EdgeHatchStyle FullHatchStyle } pub fn hatch_style(then next: NextFn(HatchStyle, a)) -> Decoder(a) { decode.enum( with: [ #("none", NoHatch), #("edge", EdgeHatchStyle), #("full", FullHatchStyle), ], then: next, ) } pub type Hatch { Hatch(style: HatchStyle, pitch: Float) } pub fn hatch(then next: NextFn(Hatch, a)) -> Decoder(a) { decode.token(named: "hatch", then: next, with: { use style <- hatch_style() use pitch <- decode.float() decode.success(Hatch(style:, pitch:)) }) } pub type ConnectPads { ConnectPads(connection_type: Option(ConnectionType), clearance: Float) } pub fn connect_pads(then next: NextFn(ConnectPads, a)) -> Decoder(a) { decode.token(named: "connect_pads", then: next, with: { use connection_type <- decode.optional(connection_type) use clearance <- decode.token_wrapper( named: "clearance", with: decode.float, ) decode.success(ConnectPads(connection_type:, clearance:)) }) } pub type ZoneKeepoutSettings { ZoneKeepoutSettings( tracks: Bool, vias: Bool, pads: Bool, copper_pour: Bool, footprints: Bool, ) } pub fn zone_keepout_settings( then next: NextFn(ZoneKeepoutSettings, a), ) -> Decoder(a) { decode.token(named: "keepout", then: next, with: { use tracks <- decode.token_wrapper(named: "tracks", with: allowed) use vias <- decode.token_wrapper(named: "vias", with: allowed) use pads <- decode.token_wrapper(named: "pads", with: allowed) use copper_pour <- decode.token_wrapper(named: "copperpour", with: allowed) use footprints <- decode.token_wrapper(named: "footprints", with: allowed) decode.success(ZoneKeepoutSettings( tracks:, vias:, pads:, copper_pour:, footprints:, )) }) } pub type FillMode { HatchedFillMode } pub fn fill_mode(then next: NextFn(FillMode, a)) -> Decoder(a) { decode.enum(with: [#("hatched", HatchedFillMode)], then: next) } pub type SmoothingStyle { ChamferSmoothingStyle FilletSmoothingStyle } pub fn smoothing_style(then next: NextFn(SmoothingStyle, a)) -> Decoder(a) { decode.enum( with: [ #("chamfer", ChamferSmoothingStyle), #("fillet", FilletSmoothingStyle), ], then: next, ) } pub type IslandRemovalMode { AlwaysRemove NeverRemove MinimumArea } pub fn island_removal_mode( then next: NextFn(IslandRemovalMode, a), ) -> Decoder(a) { decode.int_enum(with: [AlwaysRemove, NeverRemove, MinimumArea], then: next) } pub type SmoothingLevel { NoSmoothingLevel FilletSmoothingLevel ArcMinimumSmoothingLevel ArcMaximumSmoothingLevel } pub fn smoothing_level(then next: NextFn(SmoothingLevel, a)) -> Decoder(a) { decode.int_enum( with: [ NoSmoothingLevel, FilletSmoothingLevel, ArcMinimumSmoothingLevel, ArcMaximumSmoothingLevel, ], then: next, ) } pub type BorderAlgorithm { ZoneMinimumThicknessBorderAlgorithm HatchThicknessBorderAlgorithm } pub fn border_algorithm(then next: NextFn(BorderAlgorithm, a)) -> Decoder(a) { decode.int_enum( with: [ZoneMinimumThicknessBorderAlgorithm, HatchThicknessBorderAlgorithm], then: next, ) } pub type ZoneFillSettings { ZoneFillSettings( filled: Bool, mode: Option(FillMode), thermal_gap: Option(Float), thermal_bridge_width: Option(Float), smoothing: Option(SmoothingStyle), radius: Option(Float), island_removal_mode: Option(IslandRemovalMode), island_area_min: Option(Float), hatch_thickness: Option(Float), hatch_gap: Option(Float), hatch_orientation: Option(Float), hatch_smoothing_level: Option(SmoothingLevel), hatch_smoothing_value: Option(Float), hatch_border_algorithm: Option(BorderAlgorithm), hatch_min_hole_area: Option(Float), ) } pub fn zone_fill_settings(then next: NextFn(ZoneFillSettings, a)) -> Decoder(a) { decode.token(named: "fill", then: next, with: { use filled <- decode.flag("yes") use mode <- decode.optional(decode.token_wrapper( named: "mode", with: fill_mode, then: _, )) use thermal_gap <- decode.optional(decode.token_wrapper( named: "thermal_gap", with: decode.float, then: _, )) use thermal_bridge_width <- decode.optional(decode.token_wrapper( named: "thermal_bridge_width", with: decode.float, then: _, )) use smoothing <- decode.optional(decode.token_wrapper( named: "smoothing", with: smoothing_style, then: _, )) use radius <- decode.optional(decode.token_wrapper( named: "radius", with: decode.float, then: _, )) use island_removal_mode <- decode.optional(decode.token_wrapper( named: "island_removal_mode", with: island_removal_mode, then: _, )) use island_area_min <- decode.optional(decode.token_wrapper( named: "island_area_min", with: decode.float, then: _, )) use hatch_thickness <- decode.optional(decode.token_wrapper( named: "hatch_thickness", with: decode.float, then: _, )) use hatch_gap <- decode.optional(decode.token_wrapper( named: "hatch_gap", with: decode.float, then: _, )) use hatch_orientation <- decode.optional(decode.token_wrapper( named: "hatch_orientation", with: decode.float, then: _, )) use hatch_smoothing_level <- decode.optional(decode.token_wrapper( named: "hatch_smoothing_level", with: smoothing_level, then: _, )) use hatch_smoothing_value <- decode.optional(decode.token_wrapper( named: "hatch_smoothing_value", with: decode.float, then: _, )) use hatch_border_algorithm <- decode.optional(decode.token_wrapper( named: "hatch_border_algorithm", with: border_algorithm, then: _, )) use hatch_min_hole_area <- decode.optional(decode.token_wrapper( named: "hatch_min_hole_area", with: decode.float, then: _, )) decode.success(ZoneFillSettings( filled:, mode:, thermal_gap:, thermal_bridge_width:, smoothing:, radius:, island_removal_mode:, island_area_min:, hatch_thickness:, hatch_gap:, hatch_orientation:, hatch_smoothing_level:, hatch_smoothing_value:, hatch_border_algorithm:, hatch_min_hole_area:, )) }) } pub type FilledPolygon { FilledPolygon(layer: Layer, points: Points) } pub fn filled_polygon(then next: NextFn(FilledPolygon, a)) -> Decoder(a) { decode.token(named: "filled_polygon", then: next, with: { use layer <- layer() use points <- points() decode.success(FilledPolygon(layer:, points:)) }) } pub type FillSegments { FillSegments(layer: Layer, points: Points) } pub fn fill_segments(then next: NextFn(FillSegments, a)) -> Decoder(a) { decode.token(named: "fill_segments", then: next, with: { use layer <- layer() use points <- points() decode.success(FillSegments(layer:, points:)) }) } pub type ZonePlacement { ZonePlacement(enabled: Bool, sheet_name: String) } pub fn zone_placement(then next: NextFn(ZonePlacement, a)) -> Decoder(a) { decode.token(named: "placement", then: next, with: { use enabled <- decode.token_wrapper(named: "enabled", with: yes_no, then: _) use sheet_name <- decode.token_wrapper(named: "sheetname", with: decode.string, then: _) decode.success(ZonePlacement(enabled:, sheet_name:)) }) } pub type Zone { Zone( net: Int, net_name: String, layers: List(Layer), uuid: Option(Uuid), timestamp: Option(Timestamp), name: Option(String), hatch: Hatch, priority: Option(Int), connect_pads: ConnectPads, min_thickness: Float, filled_areas_thickness: Option(Bool), keepout_settings: Option(ZoneKeepoutSettings), placement: Option(ZonePlacement), fill_settings: ZoneFillSettings, polygon: PolyPoints, fill_polygons: List(FilledPolygon), fill_segments: List(FillSegments), ) } pub fn zone(then next: NextFn(Zone, a)) -> Decoder(a) { decode.token(named: "zone", then: next, with: { use net <- decode.token_wrapper(named: "net", with: decode.int) use net_name <- decode.token_wrapper(named: "net_name", with: decode.string) use layers <- decode.one_of(layer |> decode.map(list.wrap), or: [layers]) use uuid <- decode.optional(uuid) use timestamp <- decode.optional(timestamp) use name <- decode.optional(decode.token_wrapper( named: "name", with: decode.string, then: _, )) use hatch <- hatch() use priority <- decode.optional(decode.token_wrapper( named: "priority", with: decode.int, then: _, )) use connect_pads <- connect_pads() use min_thickness <- decode.token_wrapper( named: "min_thickness", with: decode.float, ) use filled_areas_thickness <- decode.optional(decode.token_wrapper( named: "filled_areas_thickness", with: yes_no, then: _, )) use keepout_settings <- decode.optional(zone_keepout_settings) use placement <- decode.optional(zone_placement) use fill_settings <- zone_fill_settings() use polygon <- decode.token_wrapper(named: "polygon", with: poly_points) use fill_polygons <- decode.list(filled_polygon) use fill_segments <- decode.list(fill_segments) decode.success(Zone( net:, net_name:, layers:, uuid:, timestamp:, name:, hatch:, priority:, connect_pads:, min_thickness:, filled_areas_thickness:, keepout_settings:, placement:, fill_settings:, polygon:, fill_polygons:, fill_segments:, )) }) } pub type Group { Group(name: String, uuid: Uuid, members: List(Uuid)) } pub fn group(then next: NextFn(Group, a)) -> Decoder(a) { decode.token(named: "group", then: next, with: { use name <- decode.string() use uuid <- uuid() use members <- decode.token_wrapper(named: "members", with: decode.list( decode.string, then: _, )) let members = list.map(members, Uuid) decode.success(Group(name:, uuid:, members:)) }) } pub type FootprintModel { FootprintModel( file: String, hide: Option(Bool), offset: XYZ, scale: XYZ, rotate: XYZ, ) } pub fn footprint_model(then next: NextFn(FootprintModel, a)) -> Decoder(a) { decode.token(named: "model", then: next, with: { use file <- decode.string() use hide <- decode.optional(hide) use offset <- decode.one_of( decode.token_wrapper(named: "offset", with: xyz, then: _), or: [decode.token_wrapper(named: "at", with: xyz, then: _)], ) use scale <- decode.token_wrapper(named: "scale", with: xyz) use rotate <- decode.token_wrapper(named: "rotate", with: xyz) decode.success(FootprintModel(file:, hide:, offset:, scale:, rotate:)) }) } pub type Footprint { Footprint( library_link: Option(String), locked: Bool, placed: Bool, layer: Layer, tedit: Option(String), uuid: Option(Uuid), position: Option(PositionIdentifier), description: Option(String), tags: Option(String), properties: List(FootprintProperty), path: Option(String), autoplace_cost_90: Option(Int), autoplace_cost_180: Option(Int), solder_mask_margin: Option(Float), solder_paste_ratio: Option(Float), solder_paste_margin: Option(Float), solder_paste_margin_ratio: Option(Float), clearance: Option(Float), zone_connect: Option(ConnectionType), thermal_width: Option(Float), thermal_gap: Option(Float), attributes: Option(FootprintAttributes), private_layers: Option(List(String)), net_tie_pad_groups: Option(List(String)), graphic_items: List(FootprintGraphicItem), pads: List(Pad), zones: List(Zone), groups: List(Group), embedded_fonts: Option(Bool), models: List(FootprintModel), ) } fn base_footprint(then next: NextFn(Footprint, a)) -> Decoder(a) { decode.of(then: next, with: { use library_link <- decode.optional(decode.string) use locked <- decode.flag("locked") use placed <- decode.flag("placed") use layer <- layer() use tedit <- decode.optional(decode.token_wrapper( named: "tedit", with: decode.name_number_string, then: _, )) use uuid <- decode.optional(uuid) use position <- decode.optional(position_identifier) use description <- decode.optional(decode.token_wrapper( named: "descr", with: decode.string, then: _, )) use tags <- decode.optional(decode.token_wrapper( named: "tags", with: decode.string, then: _, )) use properties_a <- decode.list(footprint_property) use path <- decode.optional(decode.token_wrapper( named: "path", with: decode.string, then: _, )) use attributes_a <- decode.optional(footprint_attributes) use autoplace_cost_90 <- decode.optional(decode.token_wrapper( named: "autoplace_cost90", with: decode.int, then: _, )) use autoplace_cost_180 <- decode.optional(decode.token_wrapper( named: "autoplace_cost180", with: decode.int, then: _, )) use solder_mask_margin <- decode.optional(decode.token_wrapper( named: "solder_mask_margin", with: decode.float, then: _, )) use solder_paste_ratio <- decode.optional(decode.token_wrapper( named: "solder_paste_ratio", with: decode.float, then: _, )) use solder_paste_margin <- decode.optional(decode.token_wrapper( named: "solder_paste_margin", with: decode.float, then: _, )) use solder_paste_margin_ratio <- decode.optional(decode.token_wrapper( named: "solder_paste_margin_ratio", with: decode.float, then: _, )) use properties_b <- decode.list(footprint_property) let properties = list.append(properties_a, properties_b) use clearance <- decode.optional(decode.token_wrapper( named: "clearance", with: decode.float, then: _, )) use zone_connect <- decode.optional(decode.token_wrapper( named: "zone_connect", with: connection_type, then: _, )) use thermal_width <- decode.optional(decode.token_wrapper( named: "thermal_width", with: decode.float, then: _, )) use thermal_gap <- decode.optional(decode.token_wrapper( named: "thermal_gap", with: decode.float, then: _, )) use attributes_b <- decode.optional(footprint_attributes) let attributes = attributes_a |> option.or(attributes_b) use private_layers <- decode.optional(decode.token_wrapper( named: "private_layers", with: decode.list(decode.string, then: _), then: _, )) use net_tie_pad_groups <- decode.optional(decode.token_wrapper( named: "net_tie_pad_groups", with: decode.list(decode.string, then: _), then: _, )) use graphic_items_a <- decode.list(footprint_graphic_item) use pads <- decode.list(pad) use graphic_items_b <- decode.list(footprint_graphic_item) let graphic_items = list.append(graphic_items_a, graphic_items_b) use zones <- decode.list(zone) use groups <- decode.list(group) use embedded_fonts <- decode.optional(decode.token_wrapper( named: "embedded_fonts", with: yes_no, then: _, )) use models <- decode.list(footprint_model) decode.success(Footprint( library_link:, locked:, placed:, layer:, tedit:, uuid:, position:, description:, tags:, properties:, path:, autoplace_cost_90:, autoplace_cost_180:, solder_mask_margin:, solder_paste_ratio:, solder_paste_margin:, solder_paste_margin_ratio:, clearance:, zone_connect:, thermal_width:, thermal_gap:, attributes:, private_layers:, net_tie_pad_groups:, graphic_items:, pads:, zones:, groups:, embedded_fonts:, models:, )) }) } pub fn footprint(then next: NextFn(Footprint, a)) -> Decoder(a) { decode.token_wrapper(named: "footprint", with: base_footprint, then: next) } pub type FootprintFile { FootprintFile( name: String, version: Option(Int), generator: Option(String), generator_version: Option(String), footprint: Footprint, ) } pub fn footprint_file(then next: NextFn(FootprintFile, a)) -> Decoder(a) { decode.one_of( decode.token( named: "footprint", with: { use name <- decode.string() use version <- decode.token_wrapper(named: "version", with: decode.int) let version = Some(version) use generator <- decode.token_wrapper( named: "generator", with: decode.name_string, ) let generator = Some(generator) use generator_version <- decode.optional(decode.token_wrapper( named: "generator_version", with: decode.string, then: _, )) use footprint <- base_footprint() decode.success(FootprintFile( name:, version:, generator:, generator_version:, footprint:, )) }, then: _, ), or: [ decode.token( named: "module", with: { use name <- decode.name_string() let version = None let generator = None let generator_version = None use footprint <- base_footprint() decode.success(FootprintFile( name:, version:, generator:, generator_version:, footprint:, )) }, then: _, ), ], then: next, ) } pub type SymbolProperty { SymbolProperty( key: String, value: String, id: Option(Int), position: PositionIdentifier, show_name: Bool, effects: Effects, ) } pub fn symbol_property(then next: NextFn(SymbolProperty, a)) -> Decoder(a) { decode.token(named: "property", then: next, with: { use key <- decode.string() use value <- decode.string() use id <- decode.optional(decode.token_wrapper( named: "id", with: decode.int, then: _, )) use position <- position_identifier() use show_name <- decode.optional(decode.token( named: "show_name", with: decode.success(Nil), then: _, )) let show_name = option.is_some(show_name) use effects <- effects() decode.success(SymbolProperty( key:, value:, id:, position:, show_name:, effects:, )) }) } pub type Symbol { Symbol( library_unit_id: String, extends: Option(String), power: Bool, hide_pin_numbers: Option(Bool), hide_pin_names: Option(Bool), pin_names_offset: Option(Float), exclude_from_sim: Option(Bool), in_bom: Option(Bool), on_board: Option(Bool), properties: List(SymbolProperty), graphics_items: List(SymbolGraphicItem), pins: List(SymbolPin), units: List(Symbol), unit_name: Option(String), embedded_fonts: Option(Bool), ) } fn base_symbol(then next: NextFn(Symbol, a)) -> Decoder(a) { decode.of(then: next, with: { use library_unit_id <- decode.string() use extends <- decode.optional(decode.token_wrapper( named: "extends", with: decode.string, then: _, )) use power <- decode.optional(decode.token( named: "power", with: decode.success(Nil), then: _, )) let power = option.is_some(power) use hide_pin_numbers <- decode.optional(decode.token_wrapper( named: "pin_numbers", with: decode.optional(hide, then: _), then: _, )) let hide_pin_numbers = option.flatten(hide_pin_numbers) use pin_names <- decode.optional(decode.token( named: "pin_names", with: { use offset <- decode.optional(decode.token_wrapper( named: "offset", with: decode.float, then: _, )) use hide <- decode.optional(hide) decode.success(#(offset, hide)) }, then: _, )) let hide_pin_names = option.map(pin_names, pair.second) |> option.flatten let pin_names_offset = option.then(pin_names, pair.first) use exclude_from_sim <- decode.optional(decode.token_wrapper( named: "exclude_from_sim", with: yes_no, then: _, )) use in_bom <- decode.optional(decode.token_wrapper( named: "in_bom", with: yes_no, then: _, )) use on_board <- decode.optional(decode.token_wrapper( named: "on_board", with: yes_no, then: _, )) use properties <- decode.list(symbol_property) use graphics_items <- decode.list(symbol_graphic_item) use pins <- decode.list(symbol_pin) use units <- decode.list(symbol) use unit_name <- decode.optional(decode.token_wrapper( named: "unit_name", with: decode.string, then: _, )) use embedded_fonts <- decode.optional(decode.token_wrapper( named: "embedded_fonts", with: yes_no, then: _, )) decode.success(Symbol( library_unit_id:, extends:, power:, hide_pin_numbers:, hide_pin_names:, pin_names_offset:, exclude_from_sim:, in_bom:, on_board:, properties:, graphics_items:, pins:, units:, unit_name:, embedded_fonts:, )) }) } pub fn symbol(then next: NextFn(Symbol, a)) -> Decoder(a) { decode.token_wrapper(named: "symbol", with: base_symbol, then: next) } pub type SymbolLibrary { SymbolLibrary( version: Int, generator: String, generator_version: Option(String), symbols: List(Symbol), ) } pub fn symbol_library(then next: NextFn(SymbolLibrary, a)) -> Decoder(a) { decode.token(named: "kicad_symbol_lib", then: next, with: { use version <- decode.token_wrapper(named: "version", with: decode.int) use generator <- decode.token_wrapper( named: "generator", with: decode.name_string, ) use generator_version <- decode.optional(decode.token_wrapper( named: "generator_version", with: decode.string, then: _, )) use symbols <- decode.list(symbol) decode.success(SymbolLibrary( version:, generator:, generator_version:, symbols:, )) }) }