Skip to content
This repository was archived by the owner on Apr 22, 2026. It is now read-only.

Add KiCad 8/9/10 symbol format support - #16

Merged
natarius merged 1 commit into
masterfrom
devin/1772469157-kicad-9-10-support
Mar 2, 2026
Merged

Add KiCad 8/9/10 symbol format support#16
natarius merged 1 commit into
masterfrom
devin/1772469157-kicad-9-10-support

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Mar 2, 2026

Copy link
Copy Markdown

Summary

The PEG grammar (symbol.pegjs) was missing tokens introduced in KiCad 8, 9, and 10, causing all modern KiCad symbol files to fail parsing with: "Expected 'at', 'effects', or 'id' but 's' found" (triggered by the show_name token).

Grammar changes:

  • Property level: Added show_name, do_not_autoplace, and hide as valid tokens in the property rule's rest alternatives
  • Symbol level: Added in_pos_files, duplicate_pin_numbers_are_jumpers, body_styles, embedded_fonts, and unit_name to kicad_symbol_element
  • Library level: Added embedded_fonts to kicad_symbol_lib top-level alternatives
  • unit_name: Changed from a silent/discarding rule to one that returns a proper { type, value } AST node
  • alternate: Now accepts quoted strings (string / symbol) in addition to bare symbols for pin alternate names
  • New rule definitions: embedded_fonts, in_pos_files, duplicate_pin_numbers_are_jumpers, body_styles, show_name, do_not_autoplace

Test files:

Added two real KiCad 10 symbol files from the official kicad-symbols library:

  • 14528.kicad_sym — simple symbol using extends, with show_name/do_not_autoplace/embedded_fonts
  • 4001.kicad_sym — complex multi-unit symbol with body_styles, in_pos_files, duplicate_pin_numbers_are_jumpers

All existing tests pass with no regressions.

Review & Testing Checklist for Human

  • Verify unit_name rule change doesn't break downstream consumers — previously this rule silently consumed the token; now it returns { type: "unit_name", value: ... }. Any code processing the symbol AST will now see unit_name nodes where they were previously absent. The flux-app KiCadModernSymbolParser needs to handle this.
  • Verify body_styles value shape — returns { type: "body_styles", value: { type: "string", value: "demorgan" } }. Confirm this is the only known value (KiCad docs suggest demorgan is the only option, but check if others exist).
  • Backward compatibility — manually test parsing a KiCad 5/6/7 symbol file to ensure properties without show_name/do_not_autoplace still parse correctly (existing tests cover standard files, but test against a diverse set if possible).
  • Test end-to-end in flux-app — Once flux-app is updated with the new parser version, test importing the 4001.kicad_sym file via the Flux UI and verify it doesn't throw "Could not find any compatible parts in uploaded file."

Test Plan

  1. Clone official kicad-symbols repo: git clone https://gitlab.com/kicad/libraries/kicad-symbols.git /tmp/kicad-symbols
  2. Test parsing several .kicad_sym files from different component categories with the updated parser
  3. Verify both simple symbols (extends/aliases) and complex multi-unit symbols parse without errors
  4. Import the parsed symbols into flux-app and verify they render correctly with all pins and properties

Notes

  • The symbol-parser.js diff is auto-generated from the grammar — focus review on symbol.pegjs changes
  • The parser now handles all known KiCad 8/9/10 tokens based on real files from the official library
  • A follow-up PR for flux-app will update KiCadModernSymbolParser to consume the new AST fields

Link to Devin Session: https://app.devin.ai/sessions/103ae3c52c02438aabd3955415051fa5
Requested by: @natarius


Open with Devin

Add support for new tokens introduced in KiCad 8, 9, and 10:
- show_name and do_not_autoplace in property definitions
- embedded_fonts at library and symbol level
- in_pos_files, duplicate_pin_numbers_are_jumpers, body_styles at symbol level
- unit_name now returns proper AST node
- alternate pin names support quoted strings

Includes real KiCad 9/10 test files from official kicad-symbols library.

Co-Authored-By: Matthias <matthias.chills@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Author
Original prompt from Matthias
SYSTEM:
=== BEGIN THREAD HISTORY (in #dogfooding) ===
Thea (U0AFH6R3D8D): Given the speed the EAGLE, EasyEDA and other imports (seem) to have been implemented. Could we get a KiCad Import that works with the newest filetype?  No KiCad file that was created in the last 5 year works. The last supported version seems to be KiCad 5 and soon KiCad 10 will be launching.

Giulio (U091GFANVAT): Mmm weird since we are using kicad 9 internally 

Giulio (U091GFANVAT): I think it’s a matter of correctly mapping the kicad features into flux 

Thea (U0AFH6R3D8D): Its a biig Painpoint.

Thea (U0AFH6R3D8D): CC @matthias (U0852RD7LMP)

matthias (U0852RD7LMP): What exactly doesn't work?

Thea (U0AFH6R3D8D): Import of symbols and footprints created in a recent KiCad version just fail

matthias (U0852RD7LMP): Can you put together a folder of test files please

matthias (U0852RD7LMP): This is the first time I hear about this issue

matthias (U0852RD7LMP): @Jharwin (U091GF9SA5V) @Nicolas Tzovanis (U084Q3S45U3) is this a regressions?

Nicolas Tzovanis (U084Q3S45U3): Afaik we supported up to kicad v6

Nicolas Tzovanis (U084Q3S45U3): And kicad 9 uses the same format as kicad v6 for parts. Not sure what the deal is with Kicad 10 though.

Thea (U0AFH6R3D8D): 

ATTACHMENT:"https://app.devin.ai/attachments/a644df82-7cda-43c6-b42e-26affadf9653/image.png"

Thea (U0AFH6R3D8D): Currently making a Test folder.

Nicolas Tzovanis (U084Q3S45U3): Did the format change on Kicad 10?

matthias (U0852RD7LMP): @Devin please investigate
=== END THREAD HISTORY ===

Thread URL: https://fluxaigroup.slack.com/archives/C09286X4F7Y/p1772466774920479?thread_ts=1772466774.920479&cid=C09286X4F7Y

The latest message is the one right above that tagged you.

@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 potential issues.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment thread src/symbol.pegjs
Comment on lines +30 to +31
= "(" _ type:"embedded_fonts" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 embedded_fonts boolean value always resolves to false due to double-wrapping with bool rule

The embedded_fonts rule binds value:bool, where the bool rule (src/symbol.pegjs:514-515) already returns { type: "boolean", value: value === "yes" }. The action then does value === "yes" on this object, which is always false regardless of input.

Root Cause

The bool rule at line 515 captures the raw string "yes"/"no" and transforms it into { type: "boolean", value: true/false }. When embedded_fonts labels this result as value:bool, the identifier value in the action is bound to that object — not the raw string. The comparison value === "yes" compares an object to a string and always yields false.

// Input: (embedded_fonts yes)
// bool returns: { type: "boolean", value: true }
// value === "yes" → false (object !== string)
// Result: { type: "embedded_fonts", value: { type: "boolean", value: false } } ← always false!

This means (embedded_fonts yes) and (embedded_fonts no) both parse to false. The correct fix is to pass through value directly (like hide/bold/italic do at lines 496, 512): return { type, value };.

Note: The pre-existing rules exclude_from_sim (line 67), in_bom (line 110), and on_board (line 115) have the same bug, but those are not part of this diff.

Suggested change
= "(" _ type:"embedded_fonts" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };
= "(" _ type:"embedded_fonts" _ value:bool _ ")" {
return { type, value };
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/symbol.pegjs
Comment on lines +119 to +120
= "(" _ type:"in_pos_files" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 in_pos_files boolean value always resolves to false due to double-wrapping with bool rule

Same pattern as embedded_fonts: value:bool returns an object { type: "boolean", value: true/false }, but the action compares it with value === "yes" which is always false.

Root Cause

The in_pos_files rule at line 118-120 uses value:bool then value === "yes". Since bool already transforms "yes"/"no" into { type: "boolean", value: ... }, the subsequent value === "yes" compares an object to a string and always returns false. This means (in_pos_files yes) is incorrectly parsed as false.

The fix is: return { type, value }; to pass the bool result through directly.

Suggested change
= "(" _ type:"in_pos_files" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };
return { type, value };
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/symbol.pegjs
Comment on lines +124 to +125
= "(" _ type:"duplicate_pin_numbers_are_jumpers" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 duplicate_pin_numbers_are_jumpers boolean value always resolves to false due to double-wrapping with bool rule

Same pattern: value:bool returns an object, but value === "yes" compares it to a string, always yielding false.

Root Cause

The duplicate_pin_numbers_are_jumpers rule at line 123-125 uses value:bool then value === "yes". Since bool returns { type: "boolean", value: ... }, the comparison value === "yes" is always false. This means (duplicate_pin_numbers_are_jumpers yes) is incorrectly parsed as false.

The fix is: return { type, value };

Suggested change
= "(" _ type:"duplicate_pin_numbers_are_jumpers" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };
return { type, value };
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/symbol.pegjs
Comment on lines +157 to +158
= "(" _ type:"show_name" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 show_name boolean value always resolves to false due to double-wrapping with bool rule

Same pattern: value:bool returns an object, but value === "yes" compares it to a string, always yielding false.

Root Cause

The show_name rule at line 156-158 uses value:bool then value === "yes". Since bool returns { type: "boolean", value: ... }, the comparison is always false. This means (show_name yes) is incorrectly parsed as false, and symbol properties that should display their name will not.

The fix is: return { type, value };

Suggested change
= "(" _ type:"show_name" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };
return { type, value };
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/symbol.pegjs
Comment on lines +162 to +163
= "(" _ type:"do_not_autoplace" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 do_not_autoplace boolean value always resolves to false due to double-wrapping with bool rule

Same pattern: value:bool returns an object, but value === "yes" compares it to a string, always yielding false.

Root Cause

The do_not_autoplace rule at line 161-163 uses value:bool then value === "yes". Since bool returns { type: "boolean", value: ... }, the comparison is always false. This means (do_not_autoplace yes) is incorrectly parsed as false, and properties that should not be autoplaced will lose that setting.

The fix is: return { type, value };

Suggested change
= "(" _ type:"do_not_autoplace" _ value:bool _ ")" {
return { type, value: { type: "boolean", value: value === "yes" } };
return { type, value };
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@natarius
natarius merged commit 8d5b82f into master Mar 2, 2026
4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant