///|
pub const VERSION : String = "0.1.0"
///|
pub const MAX_INPUT_BYTES : Int = 64 * 1024 * 1024
///|
pub const MAX_TOKEN_COUNT : Int = 1_000_000
///|
pub const MAX_WORD_BYTES : Int = 64 * 1024
///|
pub const MAX_EXTENDED_BLOCK_BYTES : Int = 1024 * 1024
///|
pub(all) enum Severity {
Error
Warning
} derive(Eq, Debug)
///|
pub(all) enum AnalysisStatus {
Pass
PassWithWarnings
Fail
} derive(Eq, Debug)
///|
pub(all) enum GerberUnit {
Millimeter
Inch
} derive(Eq, Debug)
///|
pub(all) struct CoordinateFormat {
integer_digits : Int
decimal_digits : Int
} derive(Eq, Debug)
///|
pub(all) enum RawTokenKind {
Word
ExtendedBlock
} derive(Eq, Debug)
///|
pub(all) struct RawToken {
kind : RawTokenKind
raw : String
line : Int
} derive(Eq, Debug)
///|
pub(all) struct CoordinateFields {
x : String?
y : String?
i : String?
j : String?
} derive(Eq, Debug)
///|
pub(all) enum PlotMode {
Linear
Clockwise
CounterClockwise
} derive(Eq, Debug)
///|
pub(all) enum Polarity {
Dark
Clear
} derive(Eq, Debug)
///|
pub(all) struct ApertureDefinition {
code : Int
template : String
parameters_raw : String?
line : Int
} derive(Eq, Debug)
///|
pub(all) enum AttributeScope {
File
Aperture
Object
} derive(Eq, Debug)
///|
pub(all) struct GerberAttribute {
scope : AttributeScope
name : String
raw_value : String?
line : Int
} derive(Eq, Debug)
///|
pub(all) enum GerberCommand {
Comment(String)
Format(CoordinateFormat)
Unit(GerberUnit)
ApertureMacro(String, String)
ApertureDefinition(ApertureDefinition)
SelectAperture(Int)
SetPlotMode(PlotMode)
MultiQuadrant
Move(CoordinateFields)
Draw(CoordinateFields)
Flash(CoordinateFields)
BeginRegion
EndRegion
SetPolarity(Polarity)
Attribute(GerberAttribute)
DeleteAttribute(String?)
EndFile
UnknownWord(String)
UnknownExtended(String)
Malformed(String)
} derive(Eq, Debug)
///|
pub(all) struct LocatedCommand {
command : GerberCommand
line : Int
} derive(Eq, Debug)
///|
pub(all) struct Issue {
code : String
severity : Severity
message : String
line : Int?
} derive(Eq, Debug)
///|
pub(all) struct GerberStatistics {
apertures : Int
aperture_macros : Int
moves : Int
draws : Int
flashes : Int
regions : Int
arc_draws : Int
comments : Int
attributes : Int
unknown_commands : Int
} derive(Eq, Debug)
///|
pub(all) struct GerberReport {
status : AnalysisStatus
unit : GerberUnit?
coordinate_format : CoordinateFormat?
file_function : String?
file_polarity : String?
generation_software : String?
statistics : GerberStatistics
issues : Array[Issue]
} derive(Eq, Debug)
///|
pub(all) enum CliCommand {
Inspect
Check
Help
Version
} derive(Eq, Debug)
///|
pub(all) struct CliConfig {
command : CliCommand
file : String?
json : Bool
} derive(Eq, Debug)
///|
pub(all) enum CliError {
Usage(String)
} derive(Eq, Debug)
///|
fn empty_statistics() -> GerberStatistics {
{
apertures: 0,
aperture_macros: 0,
moves: 0,
draws: 0,
flashes: 0,
regions: 0,
arc_draws: 0,
comments: 0,
attributes: 0,
unknown_commands: 0,
}
}
///|
fn compute_status(issues : Array[Issue]) -> AnalysisStatus {
let mut errors = 0
let mut warnings = 0
for issue in issues {
match issue.severity {
Error => errors = errors + 1
Warning => warnings = warnings + 1
}
}
if errors > 0 {
Fail
} else if warnings > 0 {
PassWithWarnings
} else {
Pass
}
}
///|
fn count_errors(issues : Array[Issue]) -> Int {
let mut n = 0
for issue in issues {
if issue.severity == Error {
n = n + 1
}
}
n
}
///|
fn count_warnings(issues : Array[Issue]) -> Int {
let mut n = 0
for issue in issues {
if issue.severity == Warning {
n = n + 1
}
}
n
}
///|
pub fn truncate_for_message(s : String) -> String {
if s.length() <= 120 {
s
} else {
s[0:120].to_owned() + "..."
}
}
///|
fn is_ascii_digit(c : Int) -> Bool {
c >= 48 && c <= 57
}
///|
fn code_unit_at(s : String, i : Int) -> Int {
s[i].to_int()
}
///|
fn safe_parse_aperture_code(s : String) -> Int? {
if s.length() == 0 {
return None
}
let mut value = 0
let mut i = 0
while i < s.length() {
let c = code_unit_at(s, i)
if !is_ascii_digit(c) {
return None
}
let digit = c - 48
if value > (2147483647 - digit) / 10 {
return None
}
value = value * 10 + digit
i = i + 1
}
if value < 10 {
None
} else {
Some(value)
}
}
///|
fn is_coordinate_integer(s : String) -> Bool {
if s.length() == 0 {
return false
}
let mut i = 0
let first = code_unit_at(s, 0)
if first == 43 || first == 45 {
i = 1
}
if i >= s.length() {
return false
}
while i < s.length() {
if !is_ascii_digit(code_unit_at(s, i)) {
return false
}
i = i + 1
}
true
}
///|
fn digit_count_of_coordinate(s : String) -> Int {
let mut i = 0
if s.length() > 0 {
let first = code_unit_at(s, 0)
if first == 43 || first == 45 {
i = 1
}
}
s.length() - i
}
///|
fn exceeds_utf8_byte_limit(s : String, limit : Int) -> Bool {
let mut bytes = 0
let mut i = 0
while i < s.length() {
let code = code_unit_at(s, i)
if code <= 0x7F {
bytes = bytes + 1
} else if code <= 0x7FF {
bytes = bytes + 2
} else if code >= 0xD800 && code <= 0xDBFF && i + 1 < s.length() {
let next = code_unit_at(s, i + 1)
if next >= 0xDC00 && next <= 0xDFFF {
bytes = bytes + 4
i = i + 1
} else {
bytes = bytes + 3
}
} else {
bytes = bytes + 3
}
if bytes > limit {
return true
}
i = i + 1
}
false
}
///|
fn status_text(status : AnalysisStatus) -> String {
match status {
Pass => "PASS"
PassWithWarnings => "PASS WITH WARNINGS"
Fail => "FAIL"
}
}
///|
fn status_json(status : AnalysisStatus) -> String {
match status {
Pass => "pass"
PassWithWarnings => "pass_with_warnings"
Fail => "fail"
}
}
///|
fn unit_text(unit : GerberUnit) -> String {
match unit {
Millimeter => "millimeter"
Inch => "inch"
}
}
///|
fn unit_json(unit : GerberUnit) -> String {
match unit {
Millimeter => "mm"
Inch => "inch"
}
}
///|
fn severity_json(severity : Severity) -> String {
match severity {
Error => "error"
Warning => "warning"
}
}
///|
fn cli_command_json(command : CliCommand) -> String {
match command {
Inspect => "inspect"
Check => "check"
Help => "help"
Version => "version"
}
}
///|
fn slice_str(s : String, start : Int, end : Int) -> String {
s[start:end].to_owned()
}
///|
fn trim_spaces(s : String) -> String {
let mut start = 0
let mut end = s.length()
while start < end {
let c = code_unit_at(s, start)
if c == 32 || c == 9 || c == 10 || c == 13 {
start = start + 1
} else {
break
}
}
while end > start {
let c = code_unit_at(s, end - 1)
if c == 32 || c == 9 || c == 10 || c == 13 {
end = end - 1
} else {
break
}
}
slice_str(s, start, end)
}
///|
fn has_prefix(s : String, prefix : String) -> Bool {
s.has_prefix(prefix)
}