-
Notifications
You must be signed in to change notification settings - Fork 0
Analysing a Repository
A step-by-step guide to writing a Crodox grammar for your own repository and interpreting the results. This page uses the Basics grammar and the Test_Repo as a worked example, but the process applies to any language or project.
Work in progress: This guide is based on the Basics grammar, which is not complete. It is a starting point meant to be extended and adapted to your needs.
Before writing any grammar, look at the files in your repository and identify the patterns:
- What file types are in the project?
- What constructs appear? (classes, functions, imports, variables, etc.)
- How do constructs nest? (functions inside classes, variables inside functions)
- How do files reference each other? (imports, includes, require)
testFile.txt
import { C2 } from './bridgeTest2.txt';
let aaa ;
class C1 (a , b , c ) {
function F1 ( V1 ) { let xxx = zzz; }
}
C1.F1(aaa);
Patterns identified:
| Pattern | Example | Construct |
|---|---|---|
import { X } from 'file' |
import { C2 } from './bridgeTest2.txt' |
Import (cross-file link) |
class X (...) { ... } |
class C1 (a , b , c ) { ... } |
Class with parameters |
function X (...) { ... } |
function F1 ( V1 ) { ... } |
Function with parameters |
let X ; or let X = Y ;
|
let xxx = zzz; |
Variable declaration |
X.Y(...) |
C1.F1(aaa) |
Method call (reference) |
Start your grammar with the file definition. This tells Crodox which files to parse and sets up the path variable for cross-file linking:
<~"FROM".txt~>
<~>
-
"FROM"is the path variable - it stores the relative path of each file -
.txtis the file extension to match
Tip: The path variable name must match between the file definition and any import references. Here both use
"FROM".
Start with the most common constructs and work inward.
Imports link files together. The key elements are the imported name and the file path:
<:import:>
import <| <<name:up>> <||> { <<name:up>> } |> from <<"FROM".txt>> <| ; <||> \n |>
<:>
Decisions made here:
-
<<name:up>>- the imported name is visible to the parent scope (so siblings can use it) -
<<"FROM".txt>>- creates the cross-file dependency -
<| <<name:up>> <||> { <<name:up>> } |>- or-statement handles bothimport Xandimport { X } -
<| ; <||> \n |>- import ends with either;or a newline
Classes have a name, optional parameters, and a body containing other objects:
<:class:>
class <<NAME:up>> ( <? <| , <||> <<NAME:down>> |> ?> ) { <-function, class, refference, variable-> }
<:>
Decisions made here:
-
<<NAME:up>>- uppercase (no dependency) with:upscope (visible to parent) -
<<NAME:down>>- parameters use:downscope (visible inside the class body only) -
<-function, class, refference, variable->- typed sub-body listing exactly which object types can appear as children
Similar structure to classes, but with a wildcard sub-body:
<:function:>
function <<NAME:up>> ( <? <| , <||> <<NAME:down>> |> ?> ) { <-function_-> }
<:>
-
<-function_->- the underscore makes this a wildcard sub-body: any object type can appear as children
Variable declarations, with an optional initializer:
<:variable:>
let <<NAME>> <? = <<'name'>> ?> ;
<:>
-
<<NAME>>- uppercase so declaring a variable does not create a dependency -
<<'name'>>- reference variable for the initializer, creates a dependency without overwriting
Method calls on objects:
<:refference:>
<<'name'>> . <<![class|function]name!>> ( <? <| , <||> |> <<'name'>> ?> ) ;
<:>
-
<<'name'>>- reference to the object being called on -
<<![class|function]name!>>- dependency selection limits the reference toclassorfunctiontypes only - Parameters use
<<'name'>>references with repeat and optional commas
- Copy the complete grammar into the Template tab and click save
- Create a Bubble linked to your repository
- Wait for parsing to complete
If the parser reports errors, check the Syntax Overview and verify your grammar matches the actual source code patterns.
After parsing, each file shows a tree of recognized objects. For testFile.txt:
FILE (FROM = ./testFile)
|- import name = C2 (:up) FROM = ./bridgeTest2
|- import name = F5 (:up) FROM = ./folder/bridgeTest
|- variable NAME = aaa
|- variable NAME = bbb
|- variable NAME = ccc
|- class NAME = C1 (:up) params: a, b, c (:down)
| |- variable NAME = hhh
| |- variable NAME = zzz
| |- function NAME = F1 (:up) param: V1 (:down)
| | |- variable NAME = xxx ref = 'zzz'
| | |- variable NAME = yyy
| |- function NAME = F2 (:up) param: V2 (:down)
| |- variable NAME = zzz ref = 'bbb'
| |- variable NAME = yyy ref = 'hhh'
|- refference 'C1' . ![class|function] F1 ( 'aaa' )
|- refference 'C1' . ![class|function] F2 ( 'ccc' )
|- refference 'C2' . ![class|function] F3 ( )
|- refference 'C2' . ![class|function] F4 ( )
What to check:
- Are all constructs recognized? If a line is missing, the grammar does not match it
- Are variable scopes correct?
:upnames should appear on imports and class/function names - Do cross-file links resolve? Import
FROMvalues should match other file paths
Tip:
F2();inbridgeTest2.txtis not parsed because it has no dot - it does not match therefferencepattern. Unmatched lines are silently skipped. To capture a new pattern, add a new object to your grammar.
Reference variables (<<'name'>>) create dependencies. Trace each one to verify it resolves correctly:
- Start at the reference location
- Search upward through parent scopes
- The first matching variable wins
| Step | Scope checked | Found? |
|---|---|---|
| 1 | F1 body | No zzz declared here |
| 2 | C1 body |
variable zzz exists |
Result: xxx depends on zzz in C1.
| Step | Scope checked | Found? |
|---|---|---|
| 1 | F2 body | No bbb here |
| 2 | C1 body | No bbb here |
| 3 | File scope |
variable bbb exists |
Result: zzz in F2 depends on bbb at file level.
When a :down parameter has the same name as an outer variable, the parameter shadows the outer one inside that scope. In bridgeTest2.txt, function F4 has parameter eee (:down), which shadows the class-level variable eee inside F4's body.
Path variables in imports create file-to-file dependencies:
-
importmatchesfrom './bridgeTest2.txt' -
<<"FROM".txt>>extracts path./bridgeTest2 - Crodox finds the file where
FROM = ./bridgeTest2 - The files are linked - imported names become available
Check that:
- Every import resolves to an existing file
- Imported names (
:upscope) are used correctly in the importing file - The dependency chain makes sense (no circular dependencies you did not intend)
Your first grammar will not capture everything. That is expected. Improve it by:
| Issue | Fix |
|---|---|
| Missing constructs | Add new objects for unmatched patterns |
| Wrong scope | Change the variable scope modifier (:up, :down, :following, etc.) |
| Too many false matches | Make the object pattern more specific (add literal tokens) |
| Comments confuse parser | Add a jump instruction for comment syntax |
| Unresolved references | Check variable types - use <<'name'>> for references, <<NAME>> for declarations |
See the full Repo Analysis for the complete parsed output of the test repository.
| Task | Grammar element |
|---|---|
| Match a file type | <~"PATH".ext~> |
| Define a construct | <:name:> ... <:> |
| Allow children |
<---> or <-type1, type2->
|
| Capture a name |
<<name>> / <<NAME>>
|
| Create a file link | <<"PATH".ext>> |
| Create a dependency | <<'name'>> |
| Handle alternatives | <| a <||> b |> |
| Handle repetition | <? ... ?> |
| Skip to a token | -->> token |
- Getting Started
- Sign-Up
- Home Screen
- Creating Your First Template
- Template Editor
- Application Navigation
- Syntax Overview
- Workflow: End-to-End
- Workflow: Test with simpleDemo
- Workflow: Build Template from angularTemp
- Demo Repositories
- Template
- Workbench
- GitHub Integration
- GitHub App Installation
- GitHub Repository Setup
- GitHub Re-linking
- Settings
- Overview
- Declarations
- Types
- Scoping