Support variables #12
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Note
This PR was mostly vibe-coded with Claude Code. It is offered as food for thought.
Add Variable Support to Mirrow DSL
This PR implements a compile-time variable system for the Mirrow DSL, enabling developers to define reusable values at the document level and reference them throughout their SVG definitions. Variables are resolved during compilation, producing clean SVG output with no runtime overhead.
Adding support for variables opens the door for compilation of Mirrow documents as components (with props) for framework libraries.
Example Usage
Implementation Strategy
The implementation follows a three-stage compilation pipeline with compile-time variable resolution:
1. Lexer Stage - Token Recognition
TokenType.DOLLARto recognize the$prefixreadVariableReference()to tokenize variable references (e.g.,$width)2. Parser Stage - AST Construction & Validation
VarsBlock- Container for variable declarations at document rootVariableDeclaration- Individual variable definition (name + value)VariableReference- Reference to a declared variableMap<string, LiteralValue>) during parsing to track declared variablesparseAttributeValue()andparseTupleItem()to handle$variablesyntax3. Compiler Stage - Variable Resolution
VariableContext(Map of variable names to resolved values)resolveValue()function that:VariableReferencenodes to concrete values@hover) and JS events (@click)Design Decisions
Compile-time Resolution: Variables are resolved during AST → SVG compilation, not at runtime. This keeps the output SVG simple, eliminates runtime overhead, and aligns with Mirrow's design-first philosophy.
Global Scope: All variables in a
varsblock are globally scoped within the document. This covers the common use case (document-level constants) and can be extended to nested scopes in the future.Supported Types: Variables can store any literal value type (numbers, strings, identifiers, tuples). Variable-to-variable references are not supported to prevent circular dependencies.
Notable Changes
Core Compiler Changes
packages/core/src/compiler/lexer.ts (+51 lines)
TokenType.DOLLARenum valuereadVariableReference()method with validation$,$123)packages/core/src/compiler/ast.ts (+22 lines)
VariableReference,VariableDeclaration, andVarsBlockinterfacesLiteralValueunion type to includeVariableReferencevarsBlockfield toRootNodepackages/core/src/compiler/parser.ts (+179 lines)
parseVarsBlock()to handlevars { ... }syntaxparseVariableDeclarations()to build symbol tableparseVariableReference()to createVariableReferenceAST nodesVariableReferencenodespackages/core/src/compiler/compiler.ts (+107 lines)
buildVariableContext()to extract variables fromVarsBlockresolveValue()for recursive variable resolutionresolveVariablesInText()for variable substitution in CSS/JS blockscreateAttributeValue()to resolve variables before processingVariableContextintoCompileContextTesting
packages/core/test/parser.test.js (+94 lines)
Added comprehensive test coverage for:
varsblocks, variable names with hyphens/underscoresAll tests pass with clear error messages and proper AST validation.
Error Handling
The implementation provides clear, actionable error messages:
Variable '$width' is not defined(with line/column)Variable 'width' is already declared(with line/column)Invalid variable reference: variable name must start with a letter or underscoreVariables can only contain literal values (strings, numbers, identifiers, or tuples)Future Enhancements
Eventually framework adapters could be built which will expose
varsas component props for (React, Vue, Svelte, etc)Testing Instructions
Expected output: