Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions examples/jbfl/complex.jbfl
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
// Apply default padding and decimal formatting to all node elements
.*.nodes[*][*] {
// Show numbers with exactly 3 decimal places (e.g., 1.000)
PadDecimals: 3;

// Pad numeric values to 6 characters wide for alignment
PadAmount: 6;
}

// Special padding for the first element in each node list (vertex names)
.*.nodes[*][0] {
/*
Vertex names can be up to 8 characters long,
so we pad them to width 8 for neat column alignment.
This improves readability by lining up numeric columns.
*/
PadAmount: 8;
}

.*.nodes[*] {
NoComplexNewLine : true;
/*
Prevent inserting newlines inside node elements with complex children.
Disable complex newlines here to keep nested structures inline.
This avoids cluttering the output with unnecessary line breaks,
making it easier to scan.
*/
NoComplexNewLine: true;
}

// Flexbodies typically contain nested lists representing grouped geometry or materials
// Keep complex nested content inline rather than breaking into multiple lines
// This makes output more compact and easier to scan given typical data patterns
.*.flexbodies[*] {
NoComplexNewLine : true;
NoComplexNewLine: true;
}
2 changes: 2 additions & 0 deletions examples/jbfl/minimal.jbfl
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
.*.nodes[*][*] {
// Pad all node values to 8 chars and force 3 decimals (e.g., 1.000)
PadAmount: 8;
PadDecimals: 3;
}

// Keep flexbodies inline (no extra newlines for nested content)
.*.flexbodies[*] {
NoComplexNewLine : true;
}
39 changes: 25 additions & 14 deletions src/Parsing/DSL.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import Data.Set qualified as S (fromList)
import Data.Text qualified as T
import Text.Megaparsec qualified as MP
import Text.Megaparsec.Byte qualified as B
import Text.Megaparsec.Byte.Lexer qualified as L (decimal)
import Text.Megaparsec.Byte.Lexer qualified as L (
decimal,
skipBlockComment,
skipLineComment,
)

objectKeyParser :: Parser NodePatternSelector
objectKeyParser = byteChar '.' *> key
Expand All @@ -50,19 +54,19 @@ arrayIndexParser = byteChar '[' *> index <* byteChar ']'
index = Selector . ArrayIndex <$> L.decimal

patternSelectorParser :: Parser NodePatternSelector
patternSelectorParser = skipWhiteSpace *> anySel <* skipWhiteSpace
where
anySel =
tryParsers
[ B.string ".*" $> AnyObjectKey
, B.string "[*]" $> AnyArrayIndex
, objectIndexParser <?> "object index"
, objectKeyParser <?> "object key"
, arrayIndexParser <?> "array index"
]
patternSelectorParser =
tryParsers
[ B.string ".*" $> AnyObjectKey
, B.string "[*]" $> AnyArrayIndex
, objectIndexParser <?> "object index"
, objectKeyParser <?> "object key"
, arrayIndexParser <?> "array index"
]

patternParser :: Parser NodePattern
patternParser = NodePattern . Seq.fromList <$> MP.some patternSelectorParser
patternParser = skipWhiteSpace *> patternSelectors <* skipWhiteSpace
where
patternSelectors = NodePattern . Seq.fromList <$> MP.some patternSelectorParser

tryDecodeKey :: [Word8] -> (Text -> Maybe SomeKey) -> Maybe SomeKey
tryDecodeKey bs f =
Expand All @@ -76,6 +80,7 @@ propertyParser (SomeKey key) = do
skipWhiteSpace
val <- parseValueForKey key
separatorParser
skipComment
let prop = SomeProperty key
in pure (SomeKey key, prop val)

Expand All @@ -84,9 +89,14 @@ parseValueForKey NoComplexNewLine = parseBool <?> "bool"
parseValueForKey PadAmount = L.decimal <?> "integer"
parseValueForKey PadDecimals = L.decimal <?> "integer"

skipComment :: Parser ()
skipComment = void . MP.many $ comment <* skipWhiteSpace
where
comment = tryParsers [L.skipLineComment "//", L.skipBlockComment "/*" "*/"]

keyPropertyPairParser :: Parser (SomeKey, SomeProperty)
keyPropertyPairParser = do
skipWhiteSpace
skipComment
offset <- MP.getOffset
key <-
MP.label "property name" $
Expand All @@ -111,12 +121,13 @@ ruleParser = do
skipWhiteSpace
props <- MP.some (MP.try keyPropertyPairParser)
_ <- byteChar '}'
skipWhiteSpace
pure (pat, M.fromList props)

ruleSetParser :: Parser RuleSet
ruleSetParser = RuleSet . M.fromListWith M.union <$> MP.some singleRuleSet
where
singleRuleSet = skipWhiteSpace *> ruleParser <* skipWhiteSpace
singleRuleSet = skipComment *> ruleParser <* skipComment

parseDSL :: ByteString -> Either Text RuleSet
parseDSL input
Expand Down