Tree-sitter grammar for the Monad programming language.
Monad is a functional programming language with support for dependent types, type classes, and algebraic data types. This grammar provides syntax highlighting, code navigation, and structural editing support for Monad source files (.mo).
- Declarations:
def,type,class,instance,struct,infix - Type system: Dependent types, implicit/explicit binders, type constraints
- Expressions: Function application, lambda abstractions,
if/then/else,match, binary operators - Do notation: Monadic sequencing with
doblocks - Comments: Line (
//) and block (/* */) comments
npm install tree-sitter-monadconst Parser = require("tree-sitter");
const Monad = require("tree-sitter-monad");
const parser = new Parser();
parser.setLanguage(Monad);
const source = `
def add (a : Nat) (b : Nat) : Nat := a + b
type Option A {
some (a : A),
none
}
`;
const tree = parser.parse(source);
console.log(tree.rootNode.toString());Install via your preferred plugin manager:
-- lazy.nvim
{
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
vim.list_extend(opts.ensure_installed, { "monad" })
vim.list_extend(opts.parsers, {
monad = {
install_info = {
url = "https://tangled.org/monad-lang.org/tree-sitter-monad",
files = { "src/parser.c" },
branch = "main",
},
},
})
end,
}Add to your languages.toml:
[[grammar]]
name = "monad"
source = { git = "https://tangled.org/monad-lang.org/tree-sitter-monad", rev = "main" }Then run hx --grammar fetch and hx --grammar build.
- Node.js >= 18
- tree-sitter CLI
Or use devbox:
devbox shell# Install dependencies
npm install
# Generate the parser
npx tree-sitter generate
# Run tests
npm test
# Start the playground
npm startThe grammar is organized into modular files under grammar/:
| File | Purpose |
|---|---|
attr.js |
Attribute syntax (@[...]) |
basic.js |
Basic tokens and precedence constants |
command.js |
Top-level declarations (def, type, struct, class, etc.) |
do.js |
Do notation and monadic constructs |
term.js |
Terms and expressions |
util.js |
Shared combinators (sep1, sep0, etc.) |
type Bool {
true,
false
}
type Result E A {
ok (a: A),
err (e: E)
}
type List A {
empty,
cons (a : A) (List A) : List A
}
def add (a : Nat) (b : Nat) : Nat := a + b
def Bool.not (b : Bool) : Bool := if b then false else true
def List.append (a b : List A) : List A :=
match a {
empty => b,
cons el_a tail => List.cons el_a (List.append tail b)
}
class Functor (F: Type -> Type) {
def map (f: A -> B) : (F A) -> F B
}
class [Functor F] Applicative (F: Type -> Type) {
def pure : A -> F A
def apply : F (A -> B) -> F A -> F B
}
instance Functor List {
def map (f : A -> B) (self: List A) : List B :=
match self {
empty => List.empty,
cons a tail => List.cons (f a) (Functor.map f tail)
}
}
infix (>>=) := Monad.bind
infix (<|) := fun_apply
infix (|>) := apply_fun
infix (++) := append
def example := do {
let x := getValue;
y <- transform x;
return y
}
def consume (!x : Resource) : Unit := release x
def maybe_use (?x : Resource) : Unit := if available then use x else noop
@[test]
def test_function := True
@[native "add"]
def native_add (a b : I64) : I64
@[deprecated {since := "1.0", reason := "use new_function"}]
def old_function := "old"
struct Config {
debug : Bool := false
timeout : I64 := 30
}
Term.hole
Term.type_
Term.con
Apache-2.0