aboutsummaryrefslogtreecommitdiff
path: root/grammar.js
diff options
context:
space:
mode:
Diffstat (limited to 'grammar.js')
-rw-r--r--grammar.js133
1 files changed, 133 insertions, 0 deletions
diff --git a/grammar.js b/grammar.js
new file mode 100644
index 0000000..e35473f
--- /dev/null
+++ b/grammar.js
@@ -0,0 +1,133 @@
+/**
+ * @file Parser for wmap Formatted Wardley Maps
+ * @author Rubén Beltrán del Río <wmap.parser@r.bdr.sh>
+ * @license AGPL-v3
+ */
+
+/// <reference types="tree-sitter-cli/dsl" />
+// @ts-check
+
+export default grammar({
+ name: "wmap",
+
+ extras: $ => [/[ \t]/],
+
+ rules: {
+ source_file: $ => repeat(
+ choice(
+ seq($.entity, $._line_ending),
+ $._line_ending
+ )
+ ),
+
+ entity: $ => choice(
+ $.component,
+ $.dependency,
+ $.note,
+ $.stage,
+ $.group,
+ $.inertia,
+ $.evolution,
+ ),
+
+ // Entities
+ component: $ => seq(
+ field('label', $.component_label),
+ field('position', $.position),
+ optional(field('shape', $.shape))
+ ),
+
+ dependency: $ => seq(
+ field('from', $.component_label),
+ field('type', $.dependency_type),
+ field('to', $.component_label)
+ ),
+
+ note: $ => seq(
+ alias($._note_keyword, 'keyword'),
+ field('position', $.position),
+ field('text', $.text)
+ ),
+
+ stage: $ => seq(
+ '[',
+ field('number', $.stage_number),
+ ']',
+ field('value', $.real_number)
+ ),
+
+ group: $ => seq(
+ alias($._group_keyword, 'keyword'),
+ field('component', $.component_label),
+ repeat(seq(',', field('component', $.component_label)))
+ ),
+
+ inertia: $ => seq(
+ alias($._inertia_keyword, 'keyword'),
+ field('component', $.component_label)
+ ),
+
+ evolution: $ => seq(
+ alias($._evolution_keyword, 'keyword'),
+ field('component', $.component_label),
+ field('sign', $.sign),
+ field('value', $.real_number)
+ ),
+
+ // Component definitions
+ position: $ => seq(
+ '(',
+ field('x', $.real_number),
+ ',',
+ field('y', $.real_number),
+ ')'
+ ),
+
+ shape: $ => seq(
+ '[',
+ $.shape_label,
+ ']'
+ ),
+
+ dependency_type: $ => choice('--', '->'),
+
+ sign: $ => choice('+', '-'),
+
+ component_label: $ => /[^\-+,\[\]()\n\r]+/,
+
+ text: $ => /[^\n\r]+/,
+
+ real_number: $ => choice(
+ /[0-9]+\.[0-9]*/,
+ /[0-9]+/,
+ /\.[0-9]+/
+ ),
+
+ stage_number: $ => choice(
+ /[Ii][Vv]/, // IV (must come before single I)
+ /[Ii][Ii][Ii]/, // III
+ /[Ii][Ii]/, // II
+ /[Ii]/ // I
+ ),
+
+ shape_label: $ => choice(
+ /[Xx]/,
+ /[Ss][Qq][Uu][Aa][Rr][Ee]/,
+ /[Tt][Rr][Ii][Aa][Nn][Gg][Ll][Ee]/,
+ /[Cc][Ii][Rr][Cc][Ll][Ee]/
+ ),
+
+ // Keywords (case-insensitive)
+ _note_keyword: $ => /\[[Nn][Oo][Tt][Ee]\]/,
+ _group_keyword: $ => /\[[Gg][Rr][Oo][Uu][Pp]\]/,
+ _inertia_keyword: $ => /\[[Ii][Nn][Ee][Rr][Tt][Ii][Aa]\]/,
+ _evolution_keyword: $ => /\[[Ee][Vv][Oo][Ll][Uu][Tt][Ii][Oo][Nn]\]/,
+
+ // Line endings (Unix LF, Windows CRLF, classic Mac CR)
+ _line_ending: $ => choice(
+ '\n', // LF
+ '\r\n', // CRLF
+ '\r' // CR
+ ),
+ }
+});