Initial commit: Add README and LICENSE
This commit is contained in:
338
grammar.js
Normal file
338
grammar.js
Normal file
@@ -0,0 +1,338 @@
|
||||
module.exports = grammar({
|
||||
name: 'stonescript',
|
||||
|
||||
rules: {
|
||||
source_file: $ => repeat($._statement),
|
||||
|
||||
_statement: $ => choice(
|
||||
// Comments first
|
||||
$.comment,
|
||||
$.block_comment,
|
||||
// Keyword-based statements (must come before generic command)
|
||||
$.variable_declaration, // 'var'
|
||||
$.function_declaration, // 'func'
|
||||
$.for_loop, // 'for'
|
||||
$.return_statement, // 'return'
|
||||
$.break_statement, // 'break'
|
||||
$.continue_statement, // 'continue'
|
||||
$.import_statement, // 'import'
|
||||
$.new_expression, // 'new'
|
||||
// Control flow
|
||||
$.conditional, // '?'
|
||||
$.else_if_clause, // ':?'
|
||||
$.else_clause, // ':'
|
||||
// Commands (after keywords!)
|
||||
$.command_statement,
|
||||
// Fallback
|
||||
$.expression_statement
|
||||
),
|
||||
|
||||
// Comments
|
||||
comment: $ => token(seq('//', /.*/)),
|
||||
|
||||
block_comment: $ => token(seq(
|
||||
'/*',
|
||||
/[^*]*\*+(?:[^/*][^*]*\*+)*/,
|
||||
'/'
|
||||
)),
|
||||
|
||||
// Variable declaration
|
||||
variable_declaration: $ => seq(
|
||||
'var',
|
||||
field('name', $.identifier),
|
||||
optional(seq('=', field('value', $._expression)))
|
||||
),
|
||||
|
||||
// Function declaration
|
||||
function_declaration: $ => seq(
|
||||
'func',
|
||||
field('name', $.identifier),
|
||||
'(',
|
||||
optional($.parameter_list),
|
||||
')',
|
||||
optional($.function_body)
|
||||
),
|
||||
|
||||
function_body: $ => seq(
|
||||
$._indent,
|
||||
repeat1($._statement),
|
||||
$._dedent
|
||||
),
|
||||
|
||||
parameter_list: $ => seq(
|
||||
$.identifier,
|
||||
repeat(seq(',', $.identifier))
|
||||
),
|
||||
|
||||
// Loops
|
||||
for_loop: $ => choice(
|
||||
seq(
|
||||
'for',
|
||||
$.identifier,
|
||||
'=',
|
||||
$._expression,
|
||||
'..',
|
||||
$._expression,
|
||||
optional($.block)
|
||||
),
|
||||
seq(
|
||||
'for',
|
||||
$.identifier,
|
||||
':',
|
||||
$._expression,
|
||||
optional($.block)
|
||||
)
|
||||
),
|
||||
|
||||
// Import
|
||||
import_statement: $ => seq(
|
||||
'import',
|
||||
$.module_path
|
||||
),
|
||||
|
||||
new_expression: $ => seq(
|
||||
'new',
|
||||
$.module_path
|
||||
),
|
||||
|
||||
module_path: $ => /[a-zA-Z_][a-zA-Z0-9_\/]*/,
|
||||
|
||||
// Control flow
|
||||
return_statement: $ => prec.right(seq(
|
||||
'return',
|
||||
optional($._expression)
|
||||
)),
|
||||
|
||||
break_statement: $ => 'break',
|
||||
|
||||
continue_statement: $ => 'continue',
|
||||
|
||||
// Conditionals
|
||||
conditional: $ => seq(
|
||||
'?',
|
||||
$._expression,
|
||||
optional($.block)
|
||||
),
|
||||
|
||||
else_if_clause: $ => seq(
|
||||
':?',
|
||||
$._expression,
|
||||
optional($.block)
|
||||
),
|
||||
|
||||
else_clause: $ => seq(
|
||||
':',
|
||||
optional($.block)
|
||||
),
|
||||
|
||||
block: $ => seq(
|
||||
$._indent,
|
||||
repeat1($._statement),
|
||||
$._dedent
|
||||
),
|
||||
|
||||
// Commands - specific patterns
|
||||
command_statement: $ => choice(
|
||||
$.equip_command,
|
||||
$.activate_command,
|
||||
$.loadout_command,
|
||||
$.brew_command,
|
||||
$.disable_enable_command,
|
||||
$.play_command,
|
||||
$.print_command
|
||||
),
|
||||
|
||||
equip_command: $ => prec.left(seq(
|
||||
choice('equip', 'equipL', 'equipR'),
|
||||
repeat1($.item_criteria)
|
||||
)),
|
||||
|
||||
item_criteria: $ => prec.left(choice(
|
||||
$.identifier,
|
||||
$.star_level,
|
||||
$.enchantment_level
|
||||
)),
|
||||
|
||||
star_level: $ => seq('*', $.number),
|
||||
|
||||
enchantment_level: $ => seq('+', $.number),
|
||||
|
||||
activate_command: $ => seq(
|
||||
'activate',
|
||||
choice(
|
||||
$.identifier,
|
||||
'P', 'L', 'R'
|
||||
)
|
||||
),
|
||||
|
||||
loadout_command: $ => seq(
|
||||
'loadout',
|
||||
$.number
|
||||
),
|
||||
|
||||
brew_command: $ => seq(
|
||||
'brew',
|
||||
$.identifier,
|
||||
repeat(seq('+', $.identifier))
|
||||
),
|
||||
|
||||
disable_enable_command: $ => prec.left(seq(
|
||||
choice('disable', 'enable'),
|
||||
choice(
|
||||
'abilities', 'hud', 'banner',
|
||||
'loadout', 'npcDialog', 'pause', 'player'
|
||||
)
|
||||
)),
|
||||
|
||||
play_command: $ => prec.left(seq(
|
||||
'play',
|
||||
$.identifier,
|
||||
optional($.number)
|
||||
)),
|
||||
|
||||
print_command: $ => prec.right(seq(
|
||||
choice('>', '>o', '>h', '>`', '>c', '>f'),
|
||||
repeat(choice(
|
||||
$.identifier,
|
||||
$.string,
|
||||
$.number,
|
||||
$.color_code,
|
||||
','
|
||||
))
|
||||
)),
|
||||
|
||||
color_code: $ => /#[a-zA-Z0-9]+/,
|
||||
|
||||
// Expressions
|
||||
expression_statement: $ => $._expression,
|
||||
|
||||
_expression: $ => choice(
|
||||
$.identifier,
|
||||
$.number,
|
||||
$.float,
|
||||
$.string,
|
||||
$.boolean,
|
||||
$.null,
|
||||
$.array,
|
||||
$.member_expression,
|
||||
$.call_expression,
|
||||
$.index_expression,
|
||||
$.unary_expression,
|
||||
$.binary_expression,
|
||||
$.update_expression,
|
||||
$.assignment_expression,
|
||||
$.parenthesized_expression,
|
||||
$.new_expression
|
||||
),
|
||||
|
||||
member_expression: $ => prec.left(15, seq(
|
||||
field('object', $._expression),
|
||||
'.',
|
||||
field('property', $.identifier)
|
||||
)),
|
||||
|
||||
call_expression: $ => prec.left(14, seq(
|
||||
field('function', $._expression),
|
||||
'(',
|
||||
optional($.argument_list),
|
||||
')'
|
||||
)),
|
||||
|
||||
argument_list: $ => sep1($.comma_sep, $._expression),
|
||||
|
||||
comma_sep: $ => ',',
|
||||
|
||||
index_expression: $ => prec.left(13, seq(
|
||||
$._expression,
|
||||
'[',
|
||||
$._expression,
|
||||
']'
|
||||
)),
|
||||
|
||||
unary_expression: $ => prec.right(12, seq(
|
||||
choice('!', '-'),
|
||||
$._expression
|
||||
)),
|
||||
|
||||
// Binary operators with proper precedence
|
||||
binary_expression: $ => choice(
|
||||
prec.left(4, seq($._expression, '|', $._expression)),
|
||||
prec.left(5, seq($._expression, '&', $._expression)),
|
||||
prec.left(7, seq($._expression, '!', $._expression)),
|
||||
prec.left(7, seq($._expression, '=', $._expression)),
|
||||
prec.left(8, seq($._expression, '<', $._expression)),
|
||||
prec.left(8, seq($._expression, '>', $._expression)),
|
||||
prec.left(8, seq($._expression, '<=', $._expression)),
|
||||
prec.left(8, seq($._expression, '>=', $._expression)),
|
||||
prec.left(9, seq($._expression, '+', $._expression)),
|
||||
prec.left(9, seq($._expression, '-', $._expression)),
|
||||
prec.left(10, seq($._expression, '*', $._expression)),
|
||||
prec.left(10, seq($._expression, '/', $._expression)),
|
||||
prec.left(11, seq($._expression, '%', $._expression))
|
||||
),
|
||||
|
||||
update_expression: $ => choice(
|
||||
prec.left(12, seq($._expression, choice('++', '--'))),
|
||||
prec.right(12, seq(choice('++', '--'), $._expression))
|
||||
),
|
||||
|
||||
assignment_expression: $ => prec.right(2, seq(
|
||||
$._expression,
|
||||
choice('=', '+=', '-=', '*=', '/='),
|
||||
$._expression
|
||||
)),
|
||||
|
||||
parenthesized_expression: $ => seq(
|
||||
'(',
|
||||
$._expression,
|
||||
')'
|
||||
),
|
||||
|
||||
// Arrays
|
||||
array: $ => seq(
|
||||
'[',
|
||||
optional(sep1($.comma_sep, $._expression)),
|
||||
optional(','),
|
||||
']'
|
||||
),
|
||||
|
||||
// Primitives
|
||||
identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
|
||||
|
||||
number: $ => /\d+/,
|
||||
|
||||
float: $ => /\d+\.\d+/,
|
||||
|
||||
string: $ => seq('"', repeat(choice(/[^"\\]/, /\\./)), '"'),
|
||||
|
||||
boolean: $ => choice('true', 'false'),
|
||||
|
||||
null: $ => 'null'
|
||||
},
|
||||
|
||||
extras: $ => [
|
||||
/\s/
|
||||
],
|
||||
|
||||
externals: $ => [
|
||||
$._newline,
|
||||
$._indent,
|
||||
$._dedent
|
||||
],
|
||||
|
||||
word: $ => $.identifier,
|
||||
|
||||
conflicts: $ => [
|
||||
[$.identifier, $.string],
|
||||
[$._expression],
|
||||
[$.command_statement],
|
||||
[$._statement, $._expression], // new_expression can be both
|
||||
[$.equip_command], // handle repeat ambiguity
|
||||
[$.binary_expression, $.assignment_expression] // = operator ambiguity
|
||||
]
|
||||
});
|
||||
|
||||
// Helper to create comma-separated lists
|
||||
function sep1(separator, rule) {
|
||||
return seq(rule, repeat(seq(separator, rule)));
|
||||
}
|
||||
Reference in New Issue
Block a user