Fix remaining legacy parsing issues

This commit is contained in:
LilyRose2798 2025-07-24 21:33:52 +10:00
parent 421924a339
commit 6029c4ea67
3 changed files with 269 additions and 154 deletions

View file

@ -1,3 +1,4 @@
import gleam/bit_array
import gleam/float
import gleam/int
import gleam/list
@ -187,7 +188,10 @@ fn do_string(source: BitArray, acc: List(UtfCodepoint)) -> Parsed(String) {
<<92, 114, rest:bits>> -> do_string(rest, [utf_codepoint_unsafe(13), ..acc])
<<92, cp:utf8_codepoint, rest:bits>> -> do_string(rest, [cp, ..acc])
<<cp:utf8_codepoint, rest:bits>> -> do_string(rest, [cp, ..acc])
source -> Error(InvalidUtf8Character(source))
source ->
Error(InvalidUtf8Character(
source |> bit_array.slice(0, 4) |> result.unwrap(source),
))
}
}
@ -195,6 +199,7 @@ type ParsedType {
ParsedInt
ParsedFloat
ParsedName
ParsedString
}
fn do_name_number(
@ -207,7 +212,7 @@ fn do_name_number(
rest,
#([utf_codepoint_unsafe(i), ..cps], case cps {
[] -> parsed_type
_ -> ParsedName
_ -> ParsedString
}),
)
<<46 as i, rest:bits>>, #(cps, parsed_type) ->
@ -215,7 +220,7 @@ fn do_name_number(
rest,
#([utf_codepoint_unsafe(i), ..cps], case parsed_type {
ParsedInt -> ParsedFloat
_ -> ParsedName
_ -> ParsedString
}),
)
<<48 as i, rest:bits>>, #(cps, parsed_type)
@ -229,62 +234,77 @@ fn do_name_number(
| <<56 as i, rest:bits>>, #(cps, parsed_type)
| <<57 as i, rest:bits>>, #(cps, parsed_type)
-> do_name_number(rest, #([utf_codepoint_unsafe(i), ..cps], parsed_type))
<<65 as i, rest:bits>>, #(cps, _)
| <<66 as i, rest:bits>>, #(cps, _)
| <<67 as i, rest:bits>>, #(cps, _)
| <<68 as i, rest:bits>>, #(cps, _)
| <<69 as i, rest:bits>>, #(cps, _)
| <<70 as i, rest:bits>>, #(cps, _)
| <<71 as i, rest:bits>>, #(cps, _)
| <<72 as i, rest:bits>>, #(cps, _)
| <<73 as i, rest:bits>>, #(cps, _)
| <<74 as i, rest:bits>>, #(cps, _)
| <<75 as i, rest:bits>>, #(cps, _)
| <<76 as i, rest:bits>>, #(cps, _)
| <<77 as i, rest:bits>>, #(cps, _)
| <<78 as i, rest:bits>>, #(cps, _)
| <<79 as i, rest:bits>>, #(cps, _)
| <<80 as i, rest:bits>>, #(cps, _)
| <<81 as i, rest:bits>>, #(cps, _)
| <<82 as i, rest:bits>>, #(cps, _)
| <<83 as i, rest:bits>>, #(cps, _)
| <<84 as i, rest:bits>>, #(cps, _)
| <<85 as i, rest:bits>>, #(cps, _)
| <<86 as i, rest:bits>>, #(cps, _)
| <<87 as i, rest:bits>>, #(cps, _)
| <<88 as i, rest:bits>>, #(cps, _)
| <<89 as i, rest:bits>>, #(cps, _)
| <<90 as i, rest:bits>>, #(cps, _)
| <<97 as i, rest:bits>>, #(cps, _)
| <<98 as i, rest:bits>>, #(cps, _)
| <<99 as i, rest:bits>>, #(cps, _)
| <<100 as i, rest:bits>>, #(cps, _)
| <<101 as i, rest:bits>>, #(cps, _)
| <<102 as i, rest:bits>>, #(cps, _)
| <<103 as i, rest:bits>>, #(cps, _)
| <<104 as i, rest:bits>>, #(cps, _)
| <<105 as i, rest:bits>>, #(cps, _)
| <<106 as i, rest:bits>>, #(cps, _)
| <<107 as i, rest:bits>>, #(cps, _)
| <<108 as i, rest:bits>>, #(cps, _)
| <<109 as i, rest:bits>>, #(cps, _)
| <<110 as i, rest:bits>>, #(cps, _)
| <<111 as i, rest:bits>>, #(cps, _)
| <<112 as i, rest:bits>>, #(cps, _)
| <<113 as i, rest:bits>>, #(cps, _)
| <<114 as i, rest:bits>>, #(cps, _)
| <<115 as i, rest:bits>>, #(cps, _)
| <<116 as i, rest:bits>>, #(cps, _)
| <<117 as i, rest:bits>>, #(cps, _)
| <<118 as i, rest:bits>>, #(cps, _)
| <<119 as i, rest:bits>>, #(cps, _)
| <<120 as i, rest:bits>>, #(cps, _)
| <<121 as i, rest:bits>>, #(cps, _)
| <<122 as i, rest:bits>>, #(cps, _)
| <<95 as i, rest:bits>>, #(cps, _)
| <<42 as i, rest:bits>>, #(cps, _)
-> do_name_number(rest, #([utf_codepoint_unsafe(i), ..cps], ParsedName))
source, #(cps, parsed_type) -> {
<<65 as i, rest:bits>>, #(cps, parsed_type)
| <<66 as i, rest:bits>>, #(cps, parsed_type)
| <<67 as i, rest:bits>>, #(cps, parsed_type)
| <<68 as i, rest:bits>>, #(cps, parsed_type)
| <<69 as i, rest:bits>>, #(cps, parsed_type)
| <<70 as i, rest:bits>>, #(cps, parsed_type)
| <<71 as i, rest:bits>>, #(cps, parsed_type)
| <<72 as i, rest:bits>>, #(cps, parsed_type)
| <<73 as i, rest:bits>>, #(cps, parsed_type)
| <<74 as i, rest:bits>>, #(cps, parsed_type)
| <<75 as i, rest:bits>>, #(cps, parsed_type)
| <<76 as i, rest:bits>>, #(cps, parsed_type)
| <<77 as i, rest:bits>>, #(cps, parsed_type)
| <<78 as i, rest:bits>>, #(cps, parsed_type)
| <<79 as i, rest:bits>>, #(cps, parsed_type)
| <<80 as i, rest:bits>>, #(cps, parsed_type)
| <<81 as i, rest:bits>>, #(cps, parsed_type)
| <<82 as i, rest:bits>>, #(cps, parsed_type)
| <<83 as i, rest:bits>>, #(cps, parsed_type)
| <<84 as i, rest:bits>>, #(cps, parsed_type)
| <<85 as i, rest:bits>>, #(cps, parsed_type)
| <<86 as i, rest:bits>>, #(cps, parsed_type)
| <<87 as i, rest:bits>>, #(cps, parsed_type)
| <<88 as i, rest:bits>>, #(cps, parsed_type)
| <<89 as i, rest:bits>>, #(cps, parsed_type)
| <<90 as i, rest:bits>>, #(cps, parsed_type)
| <<97 as i, rest:bits>>, #(cps, parsed_type)
| <<98 as i, rest:bits>>, #(cps, parsed_type)
| <<99 as i, rest:bits>>, #(cps, parsed_type)
| <<100 as i, rest:bits>>, #(cps, parsed_type)
| <<101 as i, rest:bits>>, #(cps, parsed_type)
| <<102 as i, rest:bits>>, #(cps, parsed_type)
| <<103 as i, rest:bits>>, #(cps, parsed_type)
| <<104 as i, rest:bits>>, #(cps, parsed_type)
| <<105 as i, rest:bits>>, #(cps, parsed_type)
| <<106 as i, rest:bits>>, #(cps, parsed_type)
| <<107 as i, rest:bits>>, #(cps, parsed_type)
| <<108 as i, rest:bits>>, #(cps, parsed_type)
| <<109 as i, rest:bits>>, #(cps, parsed_type)
| <<110 as i, rest:bits>>, #(cps, parsed_type)
| <<111 as i, rest:bits>>, #(cps, parsed_type)
| <<112 as i, rest:bits>>, #(cps, parsed_type)
| <<113 as i, rest:bits>>, #(cps, parsed_type)
| <<114 as i, rest:bits>>, #(cps, parsed_type)
| <<115 as i, rest:bits>>, #(cps, parsed_type)
| <<116 as i, rest:bits>>, #(cps, parsed_type)
| <<117 as i, rest:bits>>, #(cps, parsed_type)
| <<118 as i, rest:bits>>, #(cps, parsed_type)
| <<119 as i, rest:bits>>, #(cps, parsed_type)
| <<120 as i, rest:bits>>, #(cps, parsed_type)
| <<121 as i, rest:bits>>, #(cps, parsed_type)
| <<122 as i, rest:bits>>, #(cps, parsed_type)
| <<95 as i, rest:bits>>, #(cps, parsed_type)
->
do_name_number(
rest,
#([utf_codepoint_unsafe(i), ..cps], case parsed_type {
ParsedInt | ParsedFloat -> ParsedName
x -> x
}),
)
<<32, source:bits>>, #(cps, parsed_type)
| <<9, source:bits>>, #(cps, parsed_type)
| <<10, source:bits>>, #(cps, parsed_type)
| <<11, source:bits>>, #(cps, parsed_type)
| <<12, source:bits>>, #(cps, parsed_type)
| <<13, source:bits>>, #(cps, parsed_type)
| <<34, _:bits>> as source, #(cps, parsed_type)
| <<40, _:bits>> as source, #(cps, parsed_type)
| <<41, _:bits>> as source, #(cps, parsed_type)
-> {
let str = cps |> list.reverse |> string.from_utf_codepoints
case parsed_type {
ParsedInt ->
@ -298,7 +318,14 @@ fn do_name_number(
Error(Nil) -> Ok(#(Name(str), source))
}
ParsedName -> Ok(#(Name(str), source))
ParsedString -> Ok(#(String(str), source))
}
}
<<cp:utf8_codepoint, rest:bits>>, #(cps, _) ->
do_name_number(rest, #([cp, ..cps], ParsedString))
source, #(_, _) ->
Error(InvalidUtf8Character(
source |> bit_array.slice(0, 4) |> result.unwrap(source),
))
}
}

View file

@ -1,5 +1,5 @@
import gleam/list
import gleam/option.{type Option}
import gleam/option.{type Option, None, Some}
import gleam/pair
import kicad_sexpr/decode.{type Decoder, type NextFn}
@ -19,7 +19,7 @@ fn allowed(then next: NextFn(Bool, a)) -> Decoder(a) {
decode.enum(with: [#("allowed", True), #("not_allowed", False)], then: next)
}
fn fill_flag(then next: NextFn(Bool, a)) -> Decoder(a) {
fn filled(then next: NextFn(Bool, a)) -> Decoder(a) {
decode.token_wrapper(named: "fill", with: yes_no, then: next)
}
@ -52,7 +52,11 @@ fn margins(then next: NextFn(#(Float, Float, Float, Float), a)) -> Decoder(a) {
}
fn hide(then next: NextFn(Bool, a)) -> Decoder(a) {
decode.token_wrapper(named: "hide", with: yes_no, then: next)
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) {
@ -65,14 +69,19 @@ fn custom_xy(named name: String, then next: NextFn(XY, a)) -> Decoder(a) {
fn layers(then next: NextFn(List(Layer), a)) -> Decoder(a) {
decode.token(named: "layers", then: next, with: {
use layers <- decode.list(decode.name_or_string)
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))
PositionIdentifier(
x: Float,
y: Float,
angle: Option(Float),
locked: Option(Bool),
)
}
pub fn position_identifier(
@ -82,7 +91,11 @@ pub fn position_identifier(
use x <- decode.float()
use y <- decode.float()
use angle <- decode.optional(decode.float)
decode.success(PositionIdentifier(x:, y:, angle:))
use locked <- decode.optional(decode.enum(
[#("locked", True), #("unlocked", False)],
then: _,
))
decode.success(PositionIdentifier(x:, y:, angle:, locked:))
})
}
@ -257,19 +270,21 @@ pub fn stroke(then next: NextFn(Stroke, a)) -> Decoder(a) {
pub type FillType {
NoFill
SolidFillType
OutlineFillType
BackgroundFillType
}
pub fn fill_type(then next: NextFn(FillType, a)) -> Decoder(a) {
decode.token(named: "type", then: next, with: {
use value <- decode.enum([
decode.enum(
[
#("none", NoFill),
#("solid", SolidFillType),
#("outline", OutlineFillType),
#("background", BackgroundFillType),
])
decode.success(value)
})
],
then: next,
)
}
pub type Fill {
@ -278,7 +293,10 @@ pub type Fill {
pub fn fill(then next: NextFn(Fill, a)) -> Decoder(a) {
decode.token(named: "fill", then: next, with: {
use type_ <- fill_type()
use type_ <- decode.one_of(
decode.token_wrapper(named: "type", with: fill_type, then: _),
or: [fill_type],
)
decode.success(Fill(type_:))
})
}
@ -315,14 +333,14 @@ pub fn font(then next: NextFn(Font, a)) -> Decoder(a) {
))
use size <- size()
use thickness <- decode.optional(thickness)
use bold <- decode.optional(decode.token_wrapper(
named: "bold",
with: yes_no,
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.token_wrapper(
named: "italic",
with: yes_no,
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(
@ -497,7 +515,7 @@ pub type Timestamp {
pub fn timestamp(then next: NextFn(Timestamp, a)) -> Decoder(a) {
decode.token(named: "tstamp", then: next, with: {
use ts <- decode.name_string()
use ts <- decode.string()
decode.success(Timestamp(ts:))
})
}
@ -508,7 +526,7 @@ pub type Layer {
pub fn layer(then next: NextFn(Layer, a)) -> Decoder(a) {
decode.token(named: "layer", then: next, with: {
use layer <- decode.name_or_string()
use layer <- decode.name_string()
decode.success(Layer(layer:))
})
}
@ -671,7 +689,7 @@ pub type FootprintText {
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.string()
use text <- decode.name_string()
use position <- position_identifier()
use unlocked <- decode.optional(decode.token_wrapper(
named: "unlocked",
@ -734,7 +752,7 @@ pub fn footprint_text_box(then next: NextFn(FootprintTextBox, a)) -> Decoder(a)
then: _,
))
use stroke <- decode.optional(stroke)
let render_cache = option.None
let render_cache = None
use timestamp <- decode.optional(timestamp)
decode.success(FootprintTextBox(
locked:,
@ -796,8 +814,10 @@ pub type FootprintRectangle {
start: XY,
end: XY,
stroke: Option(Stroke),
fill: Option(Bool),
filled: Option(Bool),
layer: Layer,
fill: Option(Fill),
width: Option(Float),
locked: Bool,
uuid: Option(Uuid),
timestamp: Option(Timestamp),
@ -811,8 +831,12 @@ pub fn footprint_rectangle(
use start <- custom_xy("start")
use end <- custom_xy("end")
use stroke <- decode.optional(stroke)
use fill <- decode.optional(fill_flag)
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)
@ -820,8 +844,10 @@ pub fn footprint_rectangle(
start:,
end:,
stroke:,
fill:,
filled:,
layer:,
fill:,
width:,
locked:,
uuid:,
timestamp:,
@ -834,8 +860,10 @@ pub type FootprintCircle {
center: XY,
end: XY,
stroke: Option(Stroke),
fill: Option(Bool),
filled: Option(Bool),
layer: Layer,
fill: Option(Fill),
width: Option(Float),
locked: Bool,
uuid: Option(Uuid),
timestamp: Option(Timestamp),
@ -847,8 +875,12 @@ pub fn footprint_circle(then next: NextFn(FootprintCircle, a)) -> Decoder(a) {
use center <- custom_xy("center")
use end <- custom_xy("end")
use stroke <- decode.optional(stroke)
use fill <- decode.optional(fill_flag)
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)
@ -856,8 +888,10 @@ pub fn footprint_circle(then next: NextFn(FootprintCircle, a)) -> Decoder(a) {
center:,
end:,
stroke:,
fill:,
filled:,
layer:,
fill:,
width:,
locked:,
uuid:,
timestamp:,
@ -872,6 +906,7 @@ pub type FootprintArc {
end: XY,
stroke: Option(Stroke),
layer: Layer,
width: Option(Float),
locked: Bool,
uuid: Option(Uuid),
timestamp: Option(Timestamp),
@ -885,6 +920,7 @@ pub fn footprint_arc(then next: NextFn(FootprintArc, a)) -> Decoder(a) {
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)
@ -894,6 +930,7 @@ pub fn footprint_arc(then next: NextFn(FootprintArc, a)) -> Decoder(a) {
end:,
stroke:,
layer:,
width:,
locked:,
uuid:,
timestamp:,
@ -905,8 +942,10 @@ pub type FootprintPolygon {
FootprintPolygon(
points: PolyPoints,
stroke: Option(Stroke),
fill: Option(Bool),
filled: Option(Bool),
layer: Layer,
fill: Option(Fill),
width: Option(Float),
locked: Bool,
uuid: Option(Uuid),
timestamp: Option(Timestamp),
@ -917,16 +956,22 @@ 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 fill <- decode.optional(fill_flag)
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:,
fill:,
filled:,
layer:,
fill:,
width:,
locked:,
uuid:,
timestamp:,
@ -939,6 +984,7 @@ pub type FootprintCurve {
points: Points,
stroke: Option(Stroke),
layer: Layer,
width: Option(Float),
locked: Bool,
uuid: Option(Uuid),
timestamp: Option(Timestamp),
@ -950,6 +996,7 @@ pub fn footprint_curve(then next: NextFn(FootprintCurve, a)) -> Decoder(a) {
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)
@ -957,6 +1004,7 @@ pub fn footprint_curve(then next: NextFn(FootprintCurve, a)) -> Decoder(a) {
points:,
stroke:,
layer:,
width:,
locked:,
uuid:,
timestamp:,
@ -1334,7 +1382,7 @@ pub fn graphical_text_box(then next: NextFn(GraphicalTextBox, a)) -> Decoder(a)
use uuid <- decode.optional(uuid)
use effects <- effects()
use stroke <- decode.optional(stroke)
let render_cache = option.None
let render_cache = None
decode.success(GraphicalTextBox(
locked:,
text:,
@ -1393,7 +1441,7 @@ pub fn graphical_rectangle(
use end <- custom_xy("end")
use layer <- decode.optional(layer)
use width <- width()
use fill <- decode.optional(fill_flag)
use fill <- decode.optional(filled)
use uuid <- decode.optional(uuid)
decode.success(GraphicalRectangle(
start:,
@ -1423,7 +1471,7 @@ pub fn graphical_circle(then next: NextFn(GraphicalCircle, a)) -> Decoder(a) {
use end <- custom_xy("end")
use layer <- decode.optional(layer)
use width <- width()
use fill <- decode.optional(fill_flag)
use fill <- decode.optional(filled)
use uuid <- decode.optional(uuid)
decode.success(GraphicalCircle(center:, end:, layer:, width:, fill:, uuid:))
})
@ -1467,7 +1515,7 @@ pub fn graphical_polygon(then next: NextFn(GraphicalPolygon, a)) -> Decoder(a) {
use points <- poly_points()
use layer <- decode.optional(layer)
use width <- width()
use fill <- decode.optional(fill_flag)
use fill <- decode.optional(filled)
use uuid <- decode.optional(uuid)
decode.success(GraphicalPolygon(points:, layer:, width:, fill:, uuid:))
})
@ -1780,12 +1828,7 @@ pub fn symbol_pin(then next: NextFn(SymbolPin, a)) -> Decoder(a) {
use graphical_style <- pin_graphical_style()
use position <- position_identifier()
use length <- decode.token_wrapper(named: "length", with: decode.float)
use hide_flag <- decode.flag("hide")
use hide <-
case hide_flag {
True -> decode.of(with: decode.success(option.Some(True)), then: _)
False -> decode.optional(hide, then: _)
}
use hide <- decode.optional(hide)
use name <- pin_name()
use number <- pin_number()
use alternatives <- decode.list(pin_alternate)
@ -2005,7 +2048,7 @@ pub fn custom_pad_primitives(
decode.token(named: "primitives", then: next, with: {
use graphic_items <- decode.list(graphic_item)
use width <- decode.optional(width)
use fill <- decode.optional(fill_flag)
use fill <- decode.optional(filled)
decode.success(CustomPadPrimitives(graphic_items:, width:, fill:))
})
}
@ -2049,7 +2092,7 @@ pub type Pad {
pub fn pad(then next: NextFn(Pad, a)) -> Decoder(a) {
decode.token(named: "pad", then: next, with: {
use number <- decode.string()
use number <- decode.name_number_string()
use type_ <- pad_type()
use shape <- pad_shape()
use position <- position_identifier()
@ -2065,14 +2108,16 @@ pub fn pad(then next: NextFn(Pad, a)) -> Decoder(a) {
use layers <- layers()
use remove_unused_layers <- decode.optional(decode.token_wrapper(
named: "remove_unused_layers",
with: yes_no,
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: yes_no,
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,
@ -2485,6 +2530,7 @@ pub type Zone {
net_name: String,
layers: List(Layer),
uuid: Option(Uuid),
timestamp: Option(Timestamp),
name: Option(String),
hatch: Hatch,
priority: Option(Int),
@ -2506,6 +2552,7 @@ pub fn zone(then next: NextFn(Zone, a)) -> Decoder(a) {
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,
@ -2538,6 +2585,7 @@ pub fn zone(then next: NextFn(Zone, a)) -> Decoder(a) {
net_name:,
layers:,
uuid:,
timestamp:,
name:,
hatch:,
priority:,
@ -2585,7 +2633,10 @@ 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.token_wrapper(named: "offset", with: xyz)
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:))
@ -2635,7 +2686,7 @@ fn base_footprint(then next: NextFn(Footprint, a)) -> Decoder(a) {
use layer <- layer()
use tedit <- decode.optional(decode.token_wrapper(
named: "tedit",
with: decode.name_or_string,
with: decode.name_number_string,
then: _,
))
use uuid <- decode.optional(uuid)
@ -2656,6 +2707,7 @@ fn base_footprint(then next: NextFn(Footprint, a)) -> Decoder(a) {
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,
@ -2708,7 +2760,8 @@ fn base_footprint(then next: NextFn(Footprint, a)) -> Decoder(a) {
with: decode.float,
then: _,
))
use attributes <- decode.optional(footprint_attributes)
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: _),
@ -2719,8 +2772,10 @@ fn base_footprint(then next: NextFn(Footprint, a)) -> Decoder(a) {
with: decode.list(decode.string, then: _),
then: _,
))
use graphic_items <- decode.list(footprint_graphic_item)
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(
@ -2771,21 +2826,26 @@ pub fn footprint(then next: NextFn(Footprint, a)) -> Decoder(a) {
pub type FootprintFile {
FootprintFile(
name: String,
version: Int,
generator: 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.token(named: "footprint", then: next, with: {
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_or_string,
with: decode.name_string,
)
let generator = Some(generator)
use generator_version <- decode.optional(decode.token_wrapper(
named: "generator_version",
with: decode.string,
@ -2799,7 +2859,31 @@ pub fn footprint_file(then next: NextFn(FootprintFile, a)) -> Decoder(a) {
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 {
@ -2863,7 +2947,7 @@ pub type Symbol {
fn base_symbol(then next: NextFn(Symbol, a)) -> Decoder(a) {
decode.of(then: next, with: {
use library_unit_id <- decode.string
use library_unit_id <- decode.string()
use extends <- decode.optional(decode.token_wrapper(
named: "extends",
with: decode.string,
@ -2963,7 +3047,7 @@ pub fn symbol_library(then next: NextFn(SymbolLibrary, a)) -> Decoder(a) {
use version <- decode.token_wrapper(named: "version", with: decode.int)
use generator <- decode.token_wrapper(
named: "generator",
with: decode.string,
with: decode.name_string,
)
use generator_version <- decode.optional(decode.token_wrapper(
named: "generator_version",

View file

@ -2,8 +2,6 @@ import gleam/float
import gleam/int
import gleam/io
import gleam/list
// import gleam/pair
import gleam/result
import gleam/string
import gleam/time/duration
@ -18,21 +16,19 @@ pub fn main() -> Nil {
io.println("\nTesting Footprints")
let assert Ok(footprint_files) =
simplifile.get_files("/usr/share/kicad/footprints")
// test_read_parse_decode(
// footprint_files |> list.drop(0) |> list.split(10) |> pair.first,
// token.footprint_file,
// True,
// )
// test_read_parse_decode(
// ["test_files/test3.kicad_mod"],
// token.footprint_file,
// True,
// )
test_read_parse_decode(footprint_files, token.footprint_file, False)
// let footprint_files = footprint_files |> list.drop(0) |> list.take(5000)
// let footprint_files = footprint_files |> list.sample(1000)
// let footprint_files = ["test_files/test3.kicad_mod"]
test_read_parse_decode(footprint_files, token.footprint_file, True)
io.println("\nTesting Symbol Libraries")
let assert Ok(symbol_libraries) =
simplifile.get_files("/usr/share/kicad/symbols")
test_read_parse_decode(symbol_libraries, token.symbol_library, False)
// let symbol_libraries = symbol_libraries |> list.drop(0) |> list.take(20)
// let symbol_libraries = symbol_libraries |> list.sample(1000)
// let symbol_libraries = ["test_files/test3.kicad_mod"]
test_read_parse_decode(symbol_libraries, token.symbol_library, True)
gleeunit.main()
}
@ -50,20 +46,23 @@ fn print_stats(
title: String,
successes: Int,
total: Int,
num_len: Int,
start_time: Timestamp,
end_time: Timestamp,
) -> Nil {
io.println(
title
<> int.to_string(successes)
<> { int.to_string(successes) |> string.pad_start(num_len, "0") }
<> "/"
<> int.to_string(total)
<> { int.to_string(total) |> string.pad_start(num_len, "0") }
<> " ("
<> int.to_float(100 * successes) /. int.to_float(total)
<> {
int.to_float(100 * successes) /. int.to_float(total)
|> float.to_precision(1)
|> float.to_string
|> string.pad_start(5, "0")
|> string.append("%")
}
<> ") in "
<> time_taken_string(start_time, end_time),
)
@ -75,7 +74,9 @@ fn test_read_parse_decode(
print_errors: Bool,
) -> Nil {
let num_file_names = list.length(file_names)
io.println("Total: " <> int.to_string(num_file_names))
let num_file_names_str = int.to_string(num_file_names)
let num_len = string.length(num_file_names_str)
io.println("Total: " <> num_file_names_str)
let time_before_read = timestamp.system_time()
let #(successfully_read, failed_to_read) =
@ -92,6 +93,7 @@ fn test_read_parse_decode(
"Read: ",
num_successfully_read,
num_file_names,
num_len,
time_before_read,
time_after_read,
)
@ -121,6 +123,7 @@ fn test_read_parse_decode(
"Parsed: ",
num_successfully_parsed,
num_successfully_read,
num_len,
time_before_parse,
time_after_parse,
)
@ -150,6 +153,7 @@ fn test_read_parse_decode(
"Decoded: ",
num_successfully_decoded,
num_successfully_parsed,
num_len,
time_before_decode,
time_after_decode,
)