Second commit.

This commit is contained in:
2025-08-26 20:54:23 -04:00
parent 94f9c6652e
commit fad24975fd
6 changed files with 2010 additions and 49 deletions

View File

@@ -1 +0,0 @@
hello

2
examples/example.scl Normal file
View File

@@ -0,0 +1,2 @@
1 + 1
sum(1, 2, 3 + 2)

View File

@@ -1,5 +1,5 @@
/** /**
* @file Scl grammar for tree-sitter * @file SCL grammar for tree-sitter
* @author Jacob Signorovitch <jacob.signorovitch@gmail.com> * @author Jacob Signorovitch <jacob.signorovitch@gmail.com>
* @license MIT * @license MIT
*/ */
@@ -7,11 +7,108 @@
/// <reference types="tree-sitter-cli/dsl" /> /// <reference types="tree-sitter-cli/dsl" />
// @ts-check // @ts-check
// grammar.js
const PREC = {
assign: 0, // right-assoc
add: 1, // left-assoc
mul: 2, // left-assoc
call: 3,
funcdef: 4,
lambda: 5,
};
module.exports = grammar({ module.exports = grammar({
name: "scl", name: "scl",
// Whitespace is of no consequence.
extras: ($) => [/\s/],
conflicts: ($) => [[$.params, $._exp]],
rules: { rules: {
// TODO: add the actual grammar rules // A file is zero or more expressions.
source_file: $ => "hello" source_file: ($) => repeat($._exp),
}
// Everything is expressions. Makes this a lot easier.
_exp: ($) =>
choice(
$.num,
$.word,
$.binexp,
$.callexp,
$.funcdef,
$.lambda,
$.vardef,
$.parexp,
),
// Literals / identifiers.
num: (_) => /\d+/,
word: (_) => /[a-zA-Z_]\w*/,
// Binary expressions with precedence and left associativity.
binexp: ($) =>
choice(
prec.left(
PREC.add,
seq(
field("left", $._exp),
field("op", choice("+", "-")),
field("right", $._exp),
),
),
prec.left(
PREC.mul,
seq(
field("left", $._exp),
field("op", choice("*", "/")),
field("right", $._exp),
),
),
),
// Function call: prefer this over plain `word` via precedence.
callexp: ($) =>
prec(
PREC.call,
seq(field("fn", $.word), "(", optional(commaSep($._exp)), ")"),
),
// Convenient function definition (sugar): `f(x, y, ...) body`.
// Give it higher precedence than calls to resolve the shared prefix.
funcdef: ($) =>
prec(
PREC.funcdef,
seq(
field("name", $.word),
field("params", $.params),
field("body", $._exp),
),
),
// Lambda: `\(x, y, ...) body`.
lambda: ($) =>
prec(
PREC.lambda,
seq("\\", field("params", $.params), field("body", $._exp)),
),
// Variable definition / assignment: `x = expr`.
// Lowest precedence, right-associative: `a = b = c` → `a = (b = c)`.
vardef: ($) =>
prec.right(
PREC.assign,
seq(field("name", $.word), "=", field("value", $._exp)),
),
// Parameter list node used by funcdef and lambda.
params: ($) => seq("(", optional(commaSep($.word)), ")"),
// Parenthesized expression.
parexp: ($) => seq("(", $._exp, ")"),
},
}); });
function commaSep(rule) {
return seq(rule, repeat(seq(",", rule)));
}

360
src/grammar.json generated
View File

@@ -3,8 +3,357 @@
"name": "scl", "name": "scl",
"rules": { "rules": {
"source_file": { "source_file": {
"type": "STRING", "type": "REPEAT",
"value": "hello" "content": {
"type": "SYMBOL",
"name": "_exp"
}
},
"_exp": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "num"
},
{
"type": "SYMBOL",
"name": "word"
},
{
"type": "SYMBOL",
"name": "binexp"
},
{
"type": "SYMBOL",
"name": "callexp"
},
{
"type": "SYMBOL",
"name": "funcdef"
},
{
"type": "SYMBOL",
"name": "lambda"
},
{
"type": "SYMBOL",
"name": "vardef"
},
{
"type": "SYMBOL",
"name": "parexp"
}
]
},
"num": {
"type": "PATTERN",
"value": "\\d+"
},
"word": {
"type": "PATTERN",
"value": "[a-zA-Z_]\\w*"
},
"binexp": {
"type": "CHOICE",
"members": [
{
"type": "PREC_LEFT",
"value": 1,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
},
{
"type": "FIELD",
"name": "op",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "+"
},
{
"type": "STRING",
"value": "-"
}
]
}
},
{
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
}
},
{
"type": "PREC_LEFT",
"value": 2,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "left",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
},
{
"type": "FIELD",
"name": "op",
"content": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "*"
},
{
"type": "STRING",
"value": "/"
}
]
}
},
{
"type": "FIELD",
"name": "right",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
}
}
]
},
"callexp": {
"type": "PREC",
"value": 3,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "fn",
"content": {
"type": "SYMBOL",
"name": "word"
}
},
{
"type": "STRING",
"value": "("
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_exp"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "_exp"
}
]
}
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": ")"
}
]
}
},
"funcdef": {
"type": "PREC",
"value": 4,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "word"
}
},
{
"type": "FIELD",
"name": "params",
"content": {
"type": "SYMBOL",
"name": "params"
}
},
{
"type": "FIELD",
"name": "body",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
}
},
"lambda": {
"type": "PREC",
"value": 5,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "\\"
},
{
"type": "FIELD",
"name": "params",
"content": {
"type": "SYMBOL",
"name": "params"
}
},
{
"type": "FIELD",
"name": "body",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
}
},
"vardef": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "name",
"content": {
"type": "SYMBOL",
"name": "word"
}
},
{
"type": "STRING",
"value": "="
},
{
"type": "FIELD",
"name": "value",
"content": {
"type": "SYMBOL",
"name": "_exp"
}
}
]
}
},
"params": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "word"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "word"
}
]
}
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": ")"
}
]
},
"parexp": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "SYMBOL",
"name": "_exp"
},
{
"type": "STRING",
"value": ")"
}
]
} }
}, },
"extras": [ "extras": [
@@ -13,7 +362,12 @@
"value": "\\s" "value": "\\s"
} }
], ],
"conflicts": [], "conflicts": [
[
"params",
"_exp"
]
],
"precedences": [], "precedences": [],
"externals": [], "externals": [],
"inline": [], "inline": [],

470
src/node-types.json generated
View File

@@ -1,12 +1,478 @@
[ [
{
"type": "binexp",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
},
"op": {
"multiple": false,
"required": true,
"types": [
{
"type": "*",
"named": false
},
{
"type": "+",
"named": false
},
{
"type": "-",
"named": false
},
{
"type": "/",
"named": false
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
}
}
},
{
"type": "callexp",
"named": true,
"fields": {
"fn": {
"multiple": false,
"required": true,
"types": [
{
"type": "word",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
}
},
{
"type": "funcdef",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "word",
"named": true
}
]
},
"params": {
"multiple": false,
"required": true,
"types": [
{
"type": "params",
"named": true
}
]
}
}
},
{
"type": "lambda",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
},
"params": {
"multiple": false,
"required": true,
"types": [
{
"type": "params",
"named": true
}
]
}
}
},
{
"type": "params",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "word",
"named": true
}
]
}
},
{
"type": "parexp",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
}
},
{ {
"type": "source_file", "type": "source_file",
"named": true, "named": true,
"root": true, "root": true,
"fields": {} "fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
}
}, },
{ {
"type": "hello", "type": "vardef",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "word",
"named": true
}
]
},
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "binexp",
"named": true
},
{
"type": "callexp",
"named": true
},
{
"type": "funcdef",
"named": true
},
{
"type": "lambda",
"named": true
},
{
"type": "num",
"named": true
},
{
"type": "parexp",
"named": true
},
{
"type": "vardef",
"named": true
},
{
"type": "word",
"named": true
}
]
}
}
},
{
"type": "(",
"named": false "named": false
},
{
"type": ")",
"named": false
},
{
"type": "*",
"named": false
},
{
"type": "+",
"named": false
},
{
"type": ",",
"named": false
},
{
"type": "-",
"named": false
},
{
"type": "/",
"named": false
},
{
"type": "=",
"named": false
},
{
"type": "\\",
"named": false
},
{
"type": "num",
"named": true
},
{
"type": "word",
"named": true
} }
] ]

1121
src/parser.c generated

File diff suppressed because it is too large Load Diff