mirror of https://github.com/Wilfred/difftastic/
1196 lines
36 KiB
JavaScript
1196 lines
36 KiB
JavaScript
// Feature flags
|
|
|
|
// Support fpc's "public name" declaration hint, e.g.
|
|
// procedure foo; public name '_FOO';
|
|
const public_name = true;
|
|
// Support extended RTTI attributes, e.g.
|
|
// [MyAttr(42)]
|
|
// procedure Foo;
|
|
const rtti = true;
|
|
// Support Delphi's anonymous procedures & functions.
|
|
const lambda = true;
|
|
// Support fpc-specific features.
|
|
const fpc = true;
|
|
// Support delphi-specific features.
|
|
const delphi = true;
|
|
// Support FPC PasCocoa extensions (for objective c interopability)
|
|
const objc = true;
|
|
// Support generic types.
|
|
const templates = delphi || fpc;
|
|
// Try to support preprocessor better.
|
|
const use_pp = true;
|
|
|
|
// Helpers
|
|
|
|
const op = {
|
|
infix: (prio, lhs, op, rhs) => prec.left(prio, seq(
|
|
field('lhs', lhs),
|
|
field('operator', op),
|
|
field('rhs', rhs)
|
|
)),
|
|
prefix: (prio, operator, operand) => prec.left(prio, seq(
|
|
field('operator', operator),
|
|
field('operand', operand)
|
|
)),
|
|
postfix: (prio, operand, operator) => prec.left(prio, seq(
|
|
field('operand', operand),
|
|
field('operator', operator)
|
|
)),
|
|
|
|
args: (prio, entity, open, args, close) => prec.left(prio, seq(
|
|
field('entity', entity), open, field('args', args), close
|
|
))
|
|
}
|
|
|
|
function delimited1(rule, delimiter = ',', precedence=0) {
|
|
return seq(
|
|
optional(repeat1(prec(precedence,seq(rule, delimiter)))),
|
|
rule
|
|
);
|
|
}
|
|
|
|
function delimited(rule, delimiter = ',') {
|
|
return optional(delimited1(rule, delimiter));
|
|
}
|
|
|
|
// Preprocessor wrapper.
|
|
// This just supports a single `if[def] ... [else[if] ...]* endif` right now.
|
|
// It is inteded for code like this:
|
|
//
|
|
// procedure foo;
|
|
// {$ifdef bla}
|
|
// var i: integer;
|
|
// begin
|
|
// inc(i);
|
|
// end;
|
|
// {$else}
|
|
// var j: integer;
|
|
// begin
|
|
// dec(j);
|
|
// end;
|
|
// {$endif}
|
|
//
|
|
// If we don't handle this case explicitly, tree-sitter produces a completely
|
|
// broken AST, which severely messes up the syntax highlighting.
|
|
//
|
|
// Ideally, we would want to support nested ifdefs as well, but that will be
|
|
// more complex.
|
|
//
|
|
// A word of caution: It is tempting to sprinkle this macro in many more
|
|
// places, but unfortunately tihs results in a significant performance penalty.
|
|
// Use it sparingly! A general rule of thumb is to use it only in situations
|
|
// where otherwise a severly broken parse tree would be generated. For small
|
|
// errors that TreeSitter can recover from automatically, it is better not to
|
|
// use it.
|
|
function pp($, ...rule) {
|
|
if (!use_pp)
|
|
return seq(...rule);
|
|
return (
|
|
choice(
|
|
seq(...rule),
|
|
seq(
|
|
alias(/\{\$[iI][fF][^}]*\}/, $.pp),
|
|
...rule,
|
|
repeat(seq(
|
|
alias(/\{\$[eE][lL][sS][eE][^}]*\}/, $.pp),
|
|
...rule
|
|
)),
|
|
alias(/\{\$[eE][nN][dD][^}]*\}/, $.pp)
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
// tr = Trailing
|
|
// Return the trailing equivalent of a rule, aliased to the non-trailing version.
|
|
const tr = ($,rule) =>
|
|
rule[0] == '_' ? $[rule+'Tr'] : alias($[rule+'Tr'], $[rule])
|
|
|
|
|
|
function enable_if(cond, ...args) {
|
|
return cond ? args : [];
|
|
}
|
|
|
|
// Generate rules for trailing & non-trailing statements
|
|
function statements(trailing) {
|
|
let rn = x => trailing ? x + 'Tr' : x
|
|
let lastStatement = $ => trailing ? optional(tr($,'_statement')) : $._statement;
|
|
let lastStatement1= $ => trailing ? tr($,'_statement') : $._statement;
|
|
let semicolon = trailing ? [] : [';'];
|
|
|
|
return Object.fromEntries([
|
|
[rn('if'), $ => seq(
|
|
$.kIf, field('condition', $._expr), $.kThen,
|
|
field('then', lastStatement($))
|
|
)],
|
|
|
|
[rn('nestedIf'), $ => prec(1,$.if)],
|
|
|
|
[rn('ifElse'), $ => prec.right(1, seq(
|
|
$.kIf, field('condition', $._expr), $.kThen,
|
|
field('then', optional(choice(tr($,'_statement'), $.if))),
|
|
$.kElse,
|
|
field('else', lastStatement($))
|
|
))],
|
|
|
|
[rn('while'), $ => seq(
|
|
$.kWhile, field('condition', $._expr), $.kDo,
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('repeat'), $ => prec(2,seq(
|
|
$.kRepeat,
|
|
field('body', optional(tr($,'statements'))),
|
|
$.kUntil, field('condition', $._expr),
|
|
...semicolon
|
|
))],
|
|
|
|
[rn('for'), $ => seq(
|
|
$.kFor,
|
|
field('start', $.assignment),
|
|
choice($.kTo, $.kDownto),
|
|
field('end', $._expr), $.kDo,
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('foreach'), $ => seq(
|
|
$.kFor,
|
|
field('iterator', $._expr), $.kIn,
|
|
field('iterable', $._expr), $.kDo,
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('exceptionHandler'), $ => seq(
|
|
$.kOn,
|
|
field('variable', optional(seq($.identifier, ':'))),
|
|
field('exception', $.typeref), $.kDo,
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('exceptionElse'), $ => seq(
|
|
$.kElse, repeat($._statement), lastStatement($)
|
|
)],
|
|
|
|
[rn('_exceptionHandlers'), $ => seq(
|
|
repeat($.exceptionHandler),
|
|
choice($.exceptionHandler, tr($,'exceptionHandler')),
|
|
optional($.exceptionElse)
|
|
)],
|
|
|
|
[rn('try'), $ => prec(2,seq(
|
|
$.kTry,
|
|
field('try', optional(tr($,'statements'))),
|
|
choice(
|
|
field('except', seq(
|
|
$.kExcept,
|
|
optional(
|
|
choice(tr($,'statements'),
|
|
tr($,'_exceptionHandlers'))
|
|
)
|
|
)),
|
|
field('finally', seq(
|
|
$.kFinally,
|
|
optional(tr($,'statements'))
|
|
))
|
|
),
|
|
$.kEnd, ...semicolon
|
|
))],
|
|
|
|
[rn('caseCase'), $ => seq(
|
|
field('label', $.caseLabel),
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('case'), $ => prec(2,seq(
|
|
$.kCase, $._expr, $.kOf,
|
|
repeat($.caseCase),
|
|
optional(tr($,'caseCase')),
|
|
optional(seq(
|
|
$.kElse,
|
|
optional(':'),
|
|
optional(tr($,'_statements'))
|
|
)),
|
|
$.kEnd, ...semicolon
|
|
))],
|
|
|
|
[rn('block'), $ => seq(
|
|
$.kBegin,
|
|
optional(tr($,'_statements')),
|
|
$.kEnd, ...semicolon
|
|
)],
|
|
|
|
[rn('asm'), $ => seq(
|
|
$.kAsm,
|
|
optional($.asmBody),
|
|
$.kEnd, ...semicolon
|
|
)],
|
|
|
|
[rn('with'), $ => seq(
|
|
$.kWith, delimited1(field('entity', $._expr)), $.kDo,
|
|
field('body', lastStatement($))
|
|
)],
|
|
|
|
[rn('raise'), $ => seq(
|
|
$.kRaise,
|
|
field('exception', $._expr),
|
|
...semicolon
|
|
)],
|
|
|
|
[rn('statement'), $ => choice(
|
|
seq($._expr, ...semicolon),
|
|
)],
|
|
|
|
[rn('goto'), $ => seq($.kGoto, $.identifier, ...semicolon)],
|
|
|
|
[rn('_statement'), $ => choice(
|
|
...semicolon,
|
|
seq($.assignment, ...semicolon),
|
|
alias($[rn('statement')], $.statement),
|
|
alias($[rn('if')], $.if),
|
|
alias($[rn('ifElse')], $.ifElse),
|
|
alias($[rn('while')], $.while),
|
|
alias($[rn('repeat')], $.repeat),
|
|
alias($[rn('for')], $.for),
|
|
alias($[rn('foreach')], $.foreach),
|
|
alias($[rn('try')], $.try),
|
|
alias($[rn('case')], $.case),
|
|
alias($[rn('block')], $.block),
|
|
alias($[rn('with')], $.with),
|
|
alias($[rn('raise')], $.raise),
|
|
alias($[rn('goto')], $.goto),
|
|
alias($[rn('asm')], $.asm),
|
|
)],
|
|
|
|
]);
|
|
}
|
|
|
|
module.exports = grammar({
|
|
name: "pascal",
|
|
|
|
extras: $ => [$._space, $.comment, $.pp],
|
|
|
|
word: $ => $.identifier,
|
|
|
|
conflicts: $ => [
|
|
// The following conflict rules are only needed because "public" can be
|
|
// a visibility or an attribute. *sigh*
|
|
// TODO: We would probably avoid this by having separate decl* clauses
|
|
// for use inside classes and at unit scope, since the "public"
|
|
// attribute seems to only be valid for standalone routines.
|
|
...enable_if(public_name,
|
|
[$._declProc ], [ $._declOperator], [$.declConst], [$.declVar],
|
|
[$.declType], [$.declProp]
|
|
),
|
|
// RTTI attributes clash with fpc declaration hints syntax since both
|
|
// are surrounded by brackets.
|
|
...enable_if(rtti,
|
|
[ $.declProcFwd ], [ $.declVars], [ $.declConsts ], [ $.declTypes]
|
|
),
|
|
// `procedure (` could be a declaration of an anonymous procedure or
|
|
// the call of a function named "procedure" (which doesn't actually
|
|
// make sense, but for Treesitter it does), so we need another conflict
|
|
// here.
|
|
...enable_if(lambda, [ $.lambda ]),
|
|
],
|
|
|
|
rules: {
|
|
root: $ => choice(
|
|
$.program,
|
|
$.library,
|
|
$.unit,
|
|
$._definitions // For include files
|
|
),
|
|
|
|
// HIGH LEVEL ----------------------------------------------------------
|
|
|
|
program: $ => seq(
|
|
$.kProgram, $.moduleName, ';',
|
|
optional($._definitions),
|
|
tr($,'block'),
|
|
$.kEndDot
|
|
),
|
|
|
|
library: $ => seq(
|
|
$.kLibrary, $.moduleName, ';',
|
|
optional($._definitions),
|
|
choice(tr($,'block'), $.kEnd),
|
|
$.kEndDot
|
|
),
|
|
|
|
unit: $ => seq(
|
|
$.kUnit, $.moduleName, ';',
|
|
repeat(choice(
|
|
$.interface,
|
|
$.implementation,
|
|
$.initialization,
|
|
$.finalization,
|
|
)),
|
|
$.kEnd, $.kEndDot
|
|
),
|
|
|
|
interface: $ => seq($.kInterface, optional($._declarations)),
|
|
implementation: $ => seq($.kImplementation, optional($._definitions)),
|
|
initialization: $ => seq($.kInitialization, optional(tr($,'_statements'))),
|
|
finalization: $ => seq($.kFinalization, optional(tr($,'_statements'))),
|
|
|
|
moduleName: $ => delimited1($.identifier, $.kDot),
|
|
|
|
// STATEMENTS ---------------------------------------------------------
|
|
|
|
...statements(false),
|
|
...statements(true),
|
|
|
|
assignment: $ => op.infix(1,
|
|
$._expr,
|
|
choice(
|
|
$.kAssign,
|
|
...enable_if(fpc,
|
|
$.kAssignAdd, $.kAssignSub, $.kAssignMul, $.kAssignDiv
|
|
)
|
|
),
|
|
$._expr
|
|
),
|
|
|
|
label: $ => seq($.identifier, ':'),
|
|
caseLabel: $ => seq(delimited1(choice($._expr, $.range)), ':'),
|
|
|
|
_statements: $ => repeat1(choice($._statement, $.label)),
|
|
_statementsTr: $ => seq(
|
|
repeat(choice($._statement, $.label)),
|
|
choice(tr($,'_statement'), $._statement)
|
|
),
|
|
|
|
statements: $ => $._statements,
|
|
statementsTr: $ => $._statementsTr,
|
|
|
|
asmBody: $ => repeat1(choice(
|
|
///([a-zA-Z0-9_]+([eE][nN][dD])|[eE][nN][dD][a-zA-Z0-9_]+|([^eE]|[eE][^nN]|[eE][nN][^dD]))+/,
|
|
$.identifier, // Identifiers
|
|
/[0-9a-fA-F]/, // Numbers
|
|
/[.,:;+\-*\[\]<>&%$]/, // Punctuation
|
|
/\([^*]|\)/ // Parentheses that are not comments
|
|
)),
|
|
|
|
// EXPRESSIONS ---------------------------------------------------------
|
|
|
|
_expr: $ => choice(
|
|
$._ref, $.exprBinary, $.exprUnary
|
|
),
|
|
|
|
_ref: $ => choice(
|
|
...enable_if(templates && fpc,
|
|
// TODO: Ideally, the kSpecialize should be part of exprTpl,
|
|
// but for some reason this leads to a rule conflict, so for
|
|
// now we just put it here.
|
|
//
|
|
// Also, we have to write the rule in this weird weird way,
|
|
// because if we just do
|
|
//
|
|
// seq(optional($.kSpecialize), $.identifier)
|
|
//
|
|
// then we can't have a standalone identifier named
|
|
// "specialize". (Bug in tree-sitter?)
|
|
prec.left(choice(
|
|
seq($.kSpecialize, $.identifier),
|
|
seq(alias($.kSpecialize, $.identifier)),
|
|
))
|
|
),
|
|
$.identifier,
|
|
$._literal, $.inherited, $.exprDot,
|
|
$.exprBrackets, $.exprParens, $.exprSubscript, $.exprCall,
|
|
alias($.exprDeref, $.exprUnary),
|
|
alias($.exprAs, $.exprBinary),
|
|
...enable_if(templates, $.exprTpl),
|
|
...enable_if(lambda, $.lambda)
|
|
),
|
|
|
|
lambda: $ => seq(
|
|
choice($.kProcedure, $.kFunction),
|
|
field('args', optional($.declArgs)),
|
|
optional(seq(
|
|
':',
|
|
field('type', $.typeref),
|
|
)),
|
|
field('local', optional($._definitions)),
|
|
field('body', choice(tr($, 'block'), tr($, 'asm'))),
|
|
),
|
|
|
|
inherited: $ => prec.right(seq($.kInherited, optional($.identifier))),
|
|
|
|
exprDot: $ => op.infix(5, $._ref, $.kDot, $._ref),
|
|
exprDeref: $ => op.postfix(4, $._expr, $.kHat),
|
|
|
|
exprAs: $ => op.infix(3, $._expr, $.kAs, $._expr),
|
|
|
|
// Unfortunately, we can't use $.exprArgs for $.exprTpl because the
|
|
// parser cannot handle it.
|
|
//
|
|
// There are two conflicting rules:
|
|
//
|
|
// 0. Binary comparison: a < b
|
|
// 1. Template use: a < b >
|
|
// ^^^^^
|
|
// prefix
|
|
//
|
|
// In order for this to work, the prefix must produce the same nodes in
|
|
// both cases. This is not the case when we introduce a wrapper node.
|
|
//
|
|
// Example:
|
|
//
|
|
// exprBinary
|
|
// identifier
|
|
// <
|
|
// identifier
|
|
//
|
|
// vs.
|
|
//
|
|
// exprTpl
|
|
// exprArgs <-- extra node
|
|
// identifier
|
|
// <
|
|
// identifier
|
|
// >
|
|
//
|
|
// Basically the way this works is that there is a tentative node like
|
|
// "exprTplOrBinary", which looks like this:
|
|
//
|
|
// exprTplOrBinary
|
|
// identifier
|
|
// <
|
|
// identifier
|
|
//
|
|
// At this point we don't yet know what we are dealing with. The next
|
|
// token will determine whether we are dealing with a comparison or a
|
|
// template. Then the existing node is simply "renamed". Because of
|
|
// this, we can't have an extra node in only one of the branches.
|
|
//
|
|
exprTpl: $ => op.args(5, $._ref, $.kLt, delimited1($._expr, ',', 5), $.kGt),
|
|
exprSubscript: $ => op.args(5, $._ref, '[', $.exprArgs, ']' ),
|
|
exprCall: $ => op.args(5, $._ref, '(', optional($.exprArgs), ')' ),
|
|
|
|
// Pascal legacy string formatting for WriteLn(foo:4:3) etc.
|
|
legacyFormat: $ => repeat1(seq(':', $._expr)),
|
|
|
|
exprArgs: $ => delimited1(seq($._expr, optional($.legacyFormat))),
|
|
|
|
exprBinary: $ => choice(
|
|
op.infix(1, $._expr, $.kLt, $._expr),
|
|
op.infix(1, $._ref, $.kLt, $._expr),
|
|
op.infix(1, $._expr, $.kEq, $._expr),
|
|
op.infix(1, $._expr, $.kNeq, $._expr),
|
|
op.infix(1, $._expr, $.kGt, $._expr),
|
|
op.infix(1, $._expr, $.kLte, $._expr),
|
|
op.infix(1, $._expr, $.kGte, $._expr),
|
|
op.infix(1, $._expr, $.kIn, $._expr),
|
|
op.infix(1, $._expr, $.kIs, $._expr),
|
|
|
|
op.infix(2, $._expr, $.kAdd, $._expr),
|
|
op.infix(2, $._expr, $.kSub, $._expr),
|
|
op.infix(2, $._expr, $.kOr, $._expr),
|
|
op.infix(2, $._expr, $.kXor, $._expr),
|
|
|
|
op.infix(3, $._expr, $.kMul, $._expr),
|
|
op.infix(3, $._expr, $.kFdiv,$._expr),
|
|
op.infix(3, $._expr, $.kDiv, $._expr),
|
|
op.infix(3, $._expr, $.kMod, $._expr),
|
|
op.infix(3, $._expr, $.kAnd, $._expr),
|
|
op.infix(3, $._expr, $.kShl, $._expr),
|
|
op.infix(3, $._expr, $.kShr, $._expr),
|
|
),
|
|
|
|
exprUnary: $ => choice(
|
|
op.prefix(4, $.kNot, $._expr),
|
|
op.prefix(4, $.kAdd, $._expr),
|
|
op.prefix(4, $.kSub, $._expr),
|
|
op.prefix(4, $.kAt, $._expr),
|
|
),
|
|
|
|
exprParens: $ => prec.left(5,seq('(', $._expr, ')')),
|
|
|
|
// Set or array literal
|
|
exprBrackets: $ => seq(
|
|
'[', delimited(choice($._expr, $.range)), ']'
|
|
),
|
|
|
|
// TYPES ---------------------------------------------------------------
|
|
|
|
type: $ => pp($,choice(
|
|
$.typeref,
|
|
$.declMetaClass,
|
|
$.declEnum,
|
|
$.declSet,
|
|
$.declArray,
|
|
$.declFile,
|
|
$.declString,
|
|
$.declProcRef,
|
|
)),
|
|
|
|
typeref: $ => seq(
|
|
...enable_if(fpc, field('_dummy', optional($.kSpecialize))),
|
|
$._typeref
|
|
),
|
|
|
|
_typeref: $ => choice(
|
|
$.identifier, $.typerefDot,
|
|
...enable_if(templates, $.typerefTpl),
|
|
$.typerefPtr,
|
|
),
|
|
|
|
typerefDot: $ => op.infix(1,$._typeref, $.kDot, $._typeref),
|
|
typerefTpl: $ => op.args(1, $._typeref, $.kLt, $.typerefArgs, $.kGt),
|
|
typerefPtr: $ => op.prefix(1,$.kHat, $._typeref),
|
|
typerefArgs: $ => delimited1($._typeref),
|
|
|
|
// GENERIC TYPE DECLARATION --------------------------------------------
|
|
//
|
|
// E.g. Foo<A: B, C: D<E>>.XYZ<T>
|
|
// ^ ^
|
|
// Note the optional constraints, which makes this different from a
|
|
// specialization
|
|
//
|
|
// We treat regular names as a special case of generic names. I.e. if
|
|
// you see $._genericName somewhere, it doesn't mean that the name HAS
|
|
// to be generic, it could just be a regular name like "TFoobar" or
|
|
// "MyUnit.Foo".
|
|
|
|
genericDot: $ => op.infix(1,$._genericName, $.kDot, $._genericName),
|
|
genericTpl: $ => op.args(2,$._genericName, $.kLt, $.genericArgs, $.kGt),
|
|
|
|
_genericName: $ => choice(
|
|
$.identifier, $.genericDot, ...enable_if(templates, $.genericTpl)
|
|
),
|
|
genericArgs: $ => delimited1($.genericArg, ';'),
|
|
genericArg: $ => seq(
|
|
field('name', delimited1($.identifier)),
|
|
field('type', optional(seq(':', $.typeref))),
|
|
field('defaultValue', optional($.defaultValue))
|
|
),
|
|
|
|
// LITERALS -----------------------------------------------------------
|
|
|
|
_literal: $ => choice(
|
|
$.literalString,
|
|
$.literalNumber,
|
|
$.kNil, $.kTrue, $.kFalse
|
|
),
|
|
literalString: $ => repeat1($._literalString),
|
|
_literalString: $ => choice(/'[^']*'/, $.literalChar),
|
|
literalChar: $ => seq('#', $._literalInt),
|
|
literalNumber: $ => choice($._literalInt, $._literalFloat),
|
|
_literalInt: $ => choice(
|
|
token.immediate(/[-+]?[0-9]+/),
|
|
token.immediate(/\$[a-fA-F0-9]+/)
|
|
),
|
|
_literalFloat: $ => prec(10, /[-+]?[0-9]*\.?[0-9]+(e[+-]?[0-9]+)?/),
|
|
|
|
range: $ => seq(
|
|
$._expr, '..', $._expr
|
|
),
|
|
|
|
// DEFINITIONS --------------------------------------------------------
|
|
|
|
_definitions: $ => repeat1($._definition),
|
|
_definition: $ => choice(
|
|
$.declTypes, $.declVars, $.declConsts, $.defProc,
|
|
alias($.declProcFwd, $.declProc),
|
|
$.declLabels, $.declUses, $.declExports,
|
|
|
|
// Include files may consist solely of preprocessor directives
|
|
// (e.g. to include other files)
|
|
$.pp,
|
|
|
|
// Not actually valid syntax, but helps the parser recover:
|
|
prec(-1,$.blockTr)
|
|
),
|
|
|
|
defProc: $ => seq(
|
|
/*pp($,*/ field('header', $.declProc)/*)*/,
|
|
pp(
|
|
$,
|
|
field('local', optional($._definitions)),
|
|
field('body', choice(tr($, 'block'), tr($, 'asm'))),
|
|
';'
|
|
)
|
|
),
|
|
|
|
declProcFwd: $ => seq(
|
|
$._declProc,
|
|
choice(seq($.kForward, ';'), $.procExternal),
|
|
repeat($._procAttribute)
|
|
),
|
|
|
|
// DECLARATIONS -------------------------------------------------------
|
|
|
|
_visibility: $ => choice(
|
|
$.kPublished, $.kPublic, $.kProtected, $.kPrivate
|
|
),
|
|
|
|
_declarations: $ => repeat1(choice(
|
|
$.declTypes, $.declVars, $.declConsts, $.declProc, $.declProp,
|
|
alias($.declProcFwd, $.declProc),
|
|
$.declUses, $.declLabels, $.declExports
|
|
)),
|
|
_classDeclarations: $ => repeat1(choice(
|
|
$.declTypes, $.declVars, $.declConsts, $.declProc, $.declProp
|
|
)),
|
|
|
|
defaultValue: $ => seq($.kEq, $._initializer),
|
|
|
|
// Declaration sections
|
|
|
|
declUses: $ => seq($.kUses, delimited($.moduleName), ';'),
|
|
declExports: $ => seq($.kExports, delimited($.declExport), ';'),
|
|
|
|
declTypes: $ => seq(
|
|
$.kType,
|
|
repeat($.declType)
|
|
),
|
|
|
|
declVars: $ => seq(
|
|
optional($.kClass),
|
|
choice($.kVar, $.kThreadvar),
|
|
repeat($.declVar)
|
|
),
|
|
|
|
declConsts: $ => seq(
|
|
optional($.kClass),
|
|
choice($.kConst, $.kResourcestring),
|
|
repeat($.declConst),
|
|
),
|
|
|
|
// Declarations
|
|
|
|
declType: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
...enable_if(fpc, optional($.kGeneric)),
|
|
field('name', $._genericName), $.kEq,
|
|
field('type',
|
|
choice(
|
|
seq(optional($.kType), $.type),
|
|
choice($.type),
|
|
$.declClass,
|
|
$.declIntf,
|
|
$.declHelper,
|
|
)
|
|
),
|
|
';',
|
|
repeat($._procAttribute)
|
|
),
|
|
|
|
declProc: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
choice($._declProc, $._declOperator),
|
|
),
|
|
|
|
declVar: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
field('name', delimited1($.identifier)),
|
|
':',
|
|
field('type', $.type),
|
|
optional(choice(
|
|
seq($.kAbsolute, $._ref),
|
|
field('defaultValue', $.defaultValue)
|
|
)),
|
|
';',
|
|
repeat(choice($._procAttribute, $.procExternal))
|
|
),
|
|
|
|
declConst: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
field('name', $.identifier),
|
|
optional(seq(':', field('type', $.type))),
|
|
field('defaultValue', $.defaultValue),
|
|
';',
|
|
repeat($._procAttribute)
|
|
),
|
|
|
|
declLabels: $ => seq($.kLabel, delimited1($.declLabel), ';'),
|
|
declLabel: $ => field('name', $.identifier),
|
|
|
|
declExport: $ => seq($._genericName, repeat(seq(choice($.kName, $.kIndex), $._expr))),
|
|
|
|
// Type declarations
|
|
|
|
declEnum: $ => seq('(', delimited1($.declEnumValue), ')'),
|
|
declEnumValue: $ => seq(field('name', $.identifier), field('value', optional($.defaultValue))),
|
|
declSet: $ => seq($.kSet, $.kOf, $.type),
|
|
declArray: $ => seq(
|
|
optional($.kPacked),
|
|
$.kArray,
|
|
optional(seq('[', delimited(choice($.range, $._expr)), ']')),
|
|
$.kOf, $.type
|
|
),
|
|
declFile: $ => seq($.kFile, optional(seq($.kOf, $.type))),
|
|
declString: $ => prec.left(seq(
|
|
$.kString,
|
|
optional(seq('[', choice($._expr), ']'))
|
|
)),
|
|
|
|
declProcRef: $ => prec.right(1,seq(
|
|
optional(seq($.kReference, $.kTo)),
|
|
choice($.kProcedure, $.kFunction),
|
|
field('args', optional($.declArgs)),
|
|
optional(seq(
|
|
':',
|
|
field('type', $.typeref),
|
|
)),
|
|
optional(seq($.kOf, $.kObject))
|
|
)),
|
|
|
|
declMetaClass: $ => seq($.kClass, $.kOf, $.typeref),
|
|
|
|
declClass: $ => seq(
|
|
optional($.kPacked),
|
|
choice(
|
|
$.kClass, $.kRecord, $.kObject,
|
|
...enable_if(objc,
|
|
$.kObjcclass, $.kObjccategory, $.kObjcprotocol
|
|
)
|
|
),
|
|
optional(choice(
|
|
$.kAbstract, $.kSealed,
|
|
...enable_if(objc,
|
|
seq($.kExternal, optional(seq($.kName, $._expr)))
|
|
)
|
|
)),
|
|
field('parent', optional(seq('(',delimited($.typeref),')'))),
|
|
optional($._declClass)
|
|
),
|
|
|
|
declIntf: $ => seq(
|
|
optional($.kPacked),
|
|
$.kInterface,
|
|
field('parent', optional(seq('(',delimited($.typeref),')'))),
|
|
field('guid', optional($.guid)),
|
|
optional($._declClass)
|
|
),
|
|
|
|
declHelper: $ => seq(
|
|
choice($.kClass, $.kRecord, $.kType), $.kHelper,
|
|
field('parent', optional(seq('(',delimited($.typeref),')'))),
|
|
$.kFor, $.typeref,
|
|
$._declClass
|
|
),
|
|
|
|
// Stuff for class/record/interface declarations
|
|
|
|
guid: $ => prec(1,seq('[', $._ref, ']')),
|
|
|
|
_declClass: $ => seq(
|
|
optional($._declFields),
|
|
optional($._classDeclarations),
|
|
repeat($.declSection),
|
|
optional($.declVariant),
|
|
$.kEnd
|
|
),
|
|
|
|
declSection: $ => seq(
|
|
optional($.kStrict),
|
|
choice($._visibility, ...enable_if(objc, $.kRequired, $.kOptional)),
|
|
optional($._declFields),
|
|
optional($._classDeclarations)
|
|
),
|
|
|
|
_declFields: $ => repeat1($.declField),
|
|
|
|
declField: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
field('name', delimited1($.identifier)),
|
|
':',
|
|
field('type', $.type),
|
|
field('defaultValue', optional($.defaultValue)),
|
|
';'
|
|
),
|
|
|
|
declProp: $ => seq(
|
|
...enable_if(rtti, optional($.rttiAttributes)),
|
|
optional($.kClass),
|
|
$.kProperty,
|
|
field('name', $.identifier),
|
|
field('args', optional($.declPropArgs)),
|
|
':',
|
|
field('type', $.type),
|
|
repeat(choice(
|
|
field('index', seq($.kIndex, $._expr)),
|
|
field('getter', seq($.kRead, $.identifier)),
|
|
field('setter', seq($.kWrite, $.identifier)),
|
|
field('implements', seq($.kImplements, delimited($._expr))),
|
|
field('defaultValue', seq($.kDefault, $._expr)),
|
|
field('stored', seq($.kStored, $._expr)),
|
|
$.kNodefault,
|
|
)),
|
|
';',
|
|
repeat($._procAttribute)
|
|
),
|
|
|
|
declPropArgs: $ => seq('[', delimited($.declArg, ';'), ']'),
|
|
|
|
// Variant records
|
|
|
|
declVariant: $ => prec.right(seq(
|
|
$.kCase,
|
|
field('name', optional(seq($.identifier, ':'))),
|
|
field('type', $.typeref), $.kOf,
|
|
delimited1($.declVariantClause, ';'),
|
|
optional(';'),
|
|
)),
|
|
|
|
declVariantClause: $ => seq(
|
|
$.caseLabel,
|
|
'(',
|
|
choice(
|
|
seq(delimited(alias($.declVariantField, $.declField), ';'), optional(seq(';', $.declVariant))),
|
|
seq($.declVariant),
|
|
),
|
|
optional(';'),
|
|
')',
|
|
),
|
|
|
|
declVariantField: $ => seq(
|
|
field('name', delimited1($.identifier)),
|
|
':',
|
|
field('type', $.type),
|
|
field('defaultValue', optional($.defaultValue))
|
|
),
|
|
|
|
// Stuff for procedure / function / operator declarations
|
|
|
|
_declProc: $ => seq(
|
|
...enable_if(fpc, optional($.kGeneric)),
|
|
optional($.kClass),
|
|
choice($.kProcedure, $.kFunction, $.kConstructor, $.kDestructor),
|
|
field('name', $._genericName),
|
|
field('args', optional($.declArgs)),
|
|
optional(seq(
|
|
':',
|
|
field('type', $.typeref),
|
|
)),
|
|
field('assign', optional($.defaultValue)),
|
|
';',
|
|
repeat($._procAttributeNoExt)
|
|
),
|
|
|
|
_declOperator: $ => seq(
|
|
optional($.kClass),
|
|
$.kOperator,
|
|
field('name', $._operatorName),
|
|
field('args', optional($.declArgs)),
|
|
...enable_if(fpc, field('resultName', optional($.identifier))),
|
|
':',
|
|
field('type', $.type),
|
|
field('assign', optional($.defaultValue)),
|
|
';',
|
|
repeat($._procAttributeNoExt)
|
|
),
|
|
|
|
operatorDot: $ => op.infix(0, $._genericName, $.kDot, $.operatorName),
|
|
_operatorName: $ => seq(
|
|
choice(
|
|
$._genericName,
|
|
...enable_if(fpc,
|
|
$.operatorName,
|
|
alias($.operatorDot, $.genericDot)
|
|
)
|
|
)
|
|
),
|
|
operatorName: $ => choice(
|
|
$.kDot, $.kLt, $.kEq, $.kNeq, $.kGt, $.kLte, $.kGte,
|
|
$.kAdd, $.kSub, $.kMul, $.kFdiv, $.kDiv, $.kMod,
|
|
$.kAssign,
|
|
$.kOr, $.kXor, $.kAnd, $.kShl, $.kShr, $.kNot,
|
|
$.kIn,
|
|
),
|
|
|
|
declArgs: $ => seq('(', delimited($.declArg, ';'), ')'),
|
|
|
|
declArg: $ => choice(
|
|
seq(
|
|
choice($.kVar, $.kConst, $.kOut, $.kConstref),
|
|
field('name', delimited1($.identifier)),
|
|
optional(seq(
|
|
':', field('type', $.type),
|
|
field('defaultValue', optional($.defaultValue))
|
|
))
|
|
),
|
|
seq(
|
|
field('name', delimited1($.identifier)), ':',
|
|
field('type', $.type),
|
|
field('defaultValue', optional($.defaultValue))
|
|
)
|
|
),
|
|
|
|
// Attributes & declaration hints
|
|
|
|
_procAttribute: $ => /*pp($,*/choice(
|
|
seq(field('attribute', $.procAttribute), ';'),
|
|
// FPC-specific syntax, e.g. procedure myproc; [public; alias:'bla'; cdecl];
|
|
...enable_if(fpc, seq(
|
|
'[',
|
|
delimited(field('attribute', choice($.procAttribute, $.procExternal))),
|
|
']', ';'
|
|
))
|
|
)/*)*/,
|
|
_procAttributeNoExt: $ => /*pp($,*/ choice(
|
|
seq(field('attribute', $.procAttribute), ';'),
|
|
// FPC-specific syntax, e.g. procedure myproc; [public; alias:'bla'; cdecl];
|
|
...enable_if(fpc, seq('[', delimited(field('attribute', choice($.procAttribute)), ';'), ']', ';'))
|
|
)/*)*/,
|
|
|
|
procAttribute: $ => choice(
|
|
$.kStatic, $.kVirtual, $.kDynamic, $.kAbstract, $.kOverride,
|
|
$.kOverload, $.kReintroduce, $.kInline, $.kStdcall,
|
|
$.kCdecl, $.kPascal, $.kRegister, $.kSafecall, $.kAssembler,
|
|
$.kNoreturn, $.kLocal, $.kFar, $.kNear,
|
|
$.kDefault, $.kNodefault, $.kDeprecated, $.kExperimental,
|
|
|
|
seq(
|
|
choice(
|
|
seq($.kMessage, optional($.kName)),
|
|
$.kDeprecated
|
|
),
|
|
$._expr
|
|
),
|
|
|
|
...enable_if(fpc,
|
|
$.kPlatform, $.kUnimplemented,
|
|
$.kCppdecl, $.kCvar, $.kMwpascal, $.kNostackframe,
|
|
$.kInterrupt, $.kIocheck, $.kHardfloat,
|
|
$.kSoftfloat, $.kMs_abi_default, $.kMs_abi_cdecl,
|
|
$.kSaveregisters, $.kSysv_abi_default, $.kSysv_abi_cdecl,
|
|
$.kVectorcall, $.kVarargs, $.kWinapi,
|
|
...enable_if(public_name, $.kPublic),
|
|
seq(
|
|
choice(
|
|
$.kExport,
|
|
seq($.kAlias, ':'),
|
|
...enable_if(public_name, seq($.kPublic, $.kName)),
|
|
),
|
|
$._expr
|
|
)
|
|
),
|
|
),
|
|
|
|
rttiAttributes: $ => repeat1(seq(
|
|
// Note: "Identifier:" is for tagging parameters of procedures (Delphi)
|
|
'[', optional(seq($.identifier, ':')), delimited($._ref), ']'
|
|
)),
|
|
|
|
procExternal: $ => seq(
|
|
$.kExternal,
|
|
optional($._expr),
|
|
optional(seq(choice($.kName, $.kIndex), $._expr)),
|
|
...enable_if(delphi, optional($.kDelayed)),
|
|
';'
|
|
),
|
|
|
|
// INITIALIZERS --------------------------------------------------------
|
|
|
|
_initializer: $ => prec(2,seq(
|
|
choice($._expr, $.recInitializer, $.arrInitializer)
|
|
)),
|
|
|
|
// record initializer
|
|
recInitializer: $ => seq(
|
|
'(',
|
|
delimited1( $.recInitializerField, ';'),
|
|
')'
|
|
),
|
|
|
|
recInitializerField: $ => choice(
|
|
seq(field('name',$.identifier), ':', field('value', $._initializer)),
|
|
field('value', $._initializer)
|
|
),
|
|
|
|
// array initializer
|
|
arrInitializer: $ => prec(1,seq('(', delimited1($._initializer), ')')),
|
|
|
|
// TERMINAL SYMBOLS ----------------------------------------------------
|
|
|
|
kProgram: $ => /[pP][rR][oO][gG][rR][aA][mM]/,
|
|
kLibrary: $ => /[lL][iI][bB][rR][aA][rR][yY]/,
|
|
kUnit: $ => /[uU][nN][iI][tT]/,
|
|
kUses: $ => /[uU][sS][eE][sS]/,
|
|
kInterface: $ => /[iI][nN][tT][eE][rR][fF][aA][cC][eE]/,
|
|
kImplementation: $ => /[iI][mM][pP][lL][eE][mM][eE][nN][tT][aA][tT][iI][oO][nN]/,
|
|
kInitialization: $ => /[iI][nN][iI][tT][iI][aA][lL][iI][zZ][aA][tT][iI][oO][nN]/,
|
|
kFinalization: $ => /[fF][iI][nN][aA][lL][iI][zZ][aA][tT][iI][oO][nN]/,
|
|
kEndDot: $ => '.',
|
|
|
|
kBegin: $ => /[bB][eE][gG][iI][nN]/,
|
|
kEnd: $ => /[eE][nN][dD]/,
|
|
kAsm: $ => /[aA][sS][mM]/,
|
|
|
|
kVar: $ => /[vV][aA][rR]/,
|
|
kThreadvar: $ => /[tT][hH][rR][eE][aA][dD][vV][aA][rR]/,
|
|
kConst: $ => /[cC][oO][nN][sS][tT]/,
|
|
kConstref: $ => /[cC][oO][nN][sS][tT][rR][eE][fF]/,
|
|
kResourcestring: $ => /[rR][eE][sS][oO][uU][rR][cC][eE][sS][tT][rR][iI][nN][gG]/,
|
|
kOut: $ => /[oO][uU][tT]/,
|
|
kType: $ => /[tT][yY][pP][eE]/,
|
|
kLabel: $ => /[lL][aA][bB][eE][lL]/,
|
|
kExports: $ => /[eE][xX][pP][oO][rR][tT][sS]/,
|
|
|
|
kAbsolute: $ => /[aA][bB][sS][oO][lL][uU][tT][eE]/,
|
|
|
|
kProperty: $ => /[pP][rR][oO][pP][eE][rR][tT][yY]/,
|
|
kRead: $ => /[rR][eE][aA][dD]/,
|
|
kWrite: $ => /[wW][rR][iI][tT][eE]/,
|
|
kImplements: $ => /[iI][mM][pP][lL][eE][mM][eE][nN][tT][sS]/,
|
|
kDefault: $ => /[dD][eE][fF][aA][uU][lL][tT]/,
|
|
kNodefault: $ => /[nN][oO][dD][eE][fF][aA][uU][lL][tT]/,
|
|
kStored: $ => /[sS][tT][oO][rR][eE][dD]/,
|
|
kIndex: $ => /[iI][nN][dD][eE][xX]/,
|
|
|
|
kClass: $ => /[cC][lL][aA][sS][sS]/,
|
|
kInterface: $ => /[iI][nN][tT][eE][rR][fF][aA][cC][eE]/,
|
|
kObject: $ => /[oO][bB][jJ][eE][cC][tT]/,
|
|
kRecord: $ => /[rR][eE][cC][oO][rR][dD]/,
|
|
kObjcclass: $ => /[oO][bB][jJ][cC][cC][lL][aA][sS][sS]/,
|
|
kObjccategory: $ => /[oO][bB][jJ][cC][cC][aA][tT][eE][gG][oO][rR][yY]/,
|
|
kObjcprotocol: $ => /[oO][bB][jJ][cC][pP][rR][oO][tT][oO][cC][oO][lL]/,
|
|
kArray: $ => /[aA][rR][rR][aA][yY]/,
|
|
kFile: $ => /[fF][iI][lL][eE]/,
|
|
kString: $ => /[sS][tT][rR][iI][nN][gG]/,
|
|
kSet: $ => /[sS][eE][tT]/,
|
|
kOf: $ => /[oO][fF]/,
|
|
kHelper: $ => /[hH][eE][lL][pP][eE][rR]/,
|
|
kPacked: $ => /[pP][aA][cC][kK][eE][dD]/,
|
|
|
|
kGeneric: $ => /[gG][eE][nN][eE][rR][iI][cC]/,
|
|
kSpecialize: $ => /[sS][pP][eE][cC][iI][aA][lL][iI][zZ][eE]/,
|
|
|
|
kDot: $ => '.',
|
|
kLt: $ => '<',
|
|
kEq: $ => '=',
|
|
kNeq: $ => '<>',
|
|
kGt: $ => '>',
|
|
kLte: $ => '<=',
|
|
kGte: $ => '>=',
|
|
kAdd: $ => '+',
|
|
kSub: $ => '-',
|
|
kMul: $ => '*',
|
|
kFdiv: $ => '/',
|
|
kAt: $ => '@',
|
|
kHat: $ => '^',
|
|
kAssign: $ => ':=',
|
|
kAssignAdd: $ => '+=', // Freepascal
|
|
kAssignSub: $ => '-=', // Freepascal
|
|
kAssignMul: $ => '*=', // Freepascal
|
|
kAssignDiv: $ => '/=', // Freepascal
|
|
kOr: $ => /[oO][rR]/,
|
|
kXor: $ => /[xX][oO][rR]/,
|
|
kDiv: $ => /[dD][iI][vV]/,
|
|
kMod: $ => /[mM][oO][dD]/,
|
|
kAnd: $ => /[aA][nN][dD]/,
|
|
kShl: $ => /[sS][hH][lL]/,
|
|
kShr: $ => /[sS][hH][rR]/,
|
|
kNot: $ => /[nN][oO][tT]/,
|
|
kIs: $ => /[iI][sS]/,
|
|
kAs: $ => /[aA][sS]/,
|
|
kIn: $ => /[iI][nN]/,
|
|
|
|
kFor: $ => /[fF][oO][rR]/,
|
|
kTo: $ => /[tT][oO]/,
|
|
kDownto: $ => /[dD][oO][wW][nN][tT][oO]/,
|
|
kIf: $ => /[iI][fF]/,
|
|
kThen: $ => /[tT][hH][eE][nN]/,
|
|
kElse: $ => /[eE][lL][sS][eE]/,
|
|
kDo: $ => /[dD][oO]/,
|
|
kWhile: $ => /[wW][hH][iI][lL][eE]/,
|
|
kRepeat: $ => /[rR][eE][pP][eE][aA][tT]/,
|
|
kUntil: $ => /[uU][nN][tT][iI][lL]/,
|
|
kTry: $ => /[tT][rR][yY]/,
|
|
kExcept: $ => /[eE][xX][cC][eE][pP][tT]/,
|
|
kFinally: $ => /[fF][iI][nN][aA][lL][lL][yY]/,
|
|
kRaise: $ => /[rR][aA][iI][sS][eE]/,
|
|
kOn: $ => /[oO][nN]/,
|
|
kCase: $ => /[cC][aA][sS][eE]/,
|
|
kWith: $ => /[wW][iI][tT][hH]/,
|
|
kGoto: $ => /[gG][oO][tT][oO]/,
|
|
|
|
kFunction: $ => /[fF][uU][nN][cC][tT][iI][oO][nN]/,
|
|
kProcedure: $ => /[pP][rR][oO][cC][eE][dD][uU][rR][eE]/,
|
|
kConstructor: $ => /[cC][oO][nN][sS][tT][rR][uU][cC][tT][oO][rR]/,
|
|
kDestructor: $ => /[dD][eE][sS][tT][rR][uU][cC][tT][oO][rR]/,
|
|
kOperator: $ => /[oO][pP][eE][rR][aA][tT][oO][rR]/,
|
|
kReference: $ => /[rR][eE][fF][eE][rR][eE][nN][cC][eE]/,
|
|
|
|
kPublished: $ => /[pP][uU][bB][lL][iI][sS][hH][eE][dD]/,
|
|
kPublic: $ => /[pP][uU][bB][lL][iI][cC]/,
|
|
kProtected: $ => /[pP][rR][oO][tT][eE][cC][tT][eE][dD]/,
|
|
kPrivate: $ => /[pP][rR][iI][vV][aA][tT][eE]/,
|
|
kStrict: $ => /[sS][tT][rR][iI][cC][tT]/,
|
|
kRequired: $ => /[rR][eE][qQ][uU][iI][rR][eE][dD]/,
|
|
kOptional: $ => /[oO][pP][tT][iI][oO][nN][aA][lL]/,
|
|
|
|
kForward: $ => /[fF][oO][rR][wW][aA][rR][dD]/,
|
|
|
|
kStatic: $ => /[sS][tT][aA][tT][iI][cC]/,
|
|
kVirtual: $ => /[vV][iI][rR][tT][uU][aA][lL]/,
|
|
kAbstract: $ => /[aA][bB][sS][tT][rR][aA][cC][tT]/,
|
|
kSealed: $ => /[sS][eE][lL][eE][dD]/,
|
|
kDynamic: $ => /[dD][yY][nN][aA][mM][iI][cC]/,
|
|
kOverride: $ => /[oO][vV][eE][rR][rR][iI][dD][eE]/,
|
|
kOverload: $ => /[oO][vV][eE][rR][lL][oO][aA][dD]/,
|
|
kReintroduce: $ => /[rR][eE][iI][nN][tT][rR][oO][dD][uU][cC][eE]/,
|
|
kInherited: $ => /[iI][nN][hH][eE][rR][iI][tT][eE][dD]/,
|
|
kInline: $ => /[iI][nN][lL][iI][nN][eE]/,
|
|
|
|
kStdcall: $ => /[sS][tT][dD][cC][aA][lL][lL]/,
|
|
kCdecl: $ => /[cC][dD][eE][cC][lL]/,
|
|
kCppdecl: $ => /[cC][pP][pP][dD][eE][cC][lL]/,
|
|
kPascal: $ => /[pP][aA][sS][cC][aA][lL]/,
|
|
kRegister: $ => /[rR][eE][gG][iI][sS][tT][eE][rR]/,
|
|
kMwpascal: $ => /[mM][wW][pP][aA][sS][cC][aA][lL]/,
|
|
kExternal: $ => /[eE][xX][tT][eE][rR][nN][aA][lL]/,
|
|
kName: $ => /[nN][aA][mM][eE]/,
|
|
kMessage: $ => /[mM][eE][sS][sS][aA][gG][eE]/,
|
|
kDeprecated: $ => /[dD][eE][pP][rR][eE][cC][aA][tT][eE][dD]/,
|
|
kExperimental: $ => /[eE][xX][pP][eE][rR][iI][mM][eE][nN][tT][aA][lL]/,
|
|
kPlatform: $ => /[pP][lL][aA][tT][fF][oO][rR][mM]/,
|
|
kUnimplemented: $ => /[uU][nN][iI][mM][pP][lL][eE][mM][eE][nN][tT][eE][dD]/,
|
|
kCvar: $ => /[cC][vV][aA][rR]/,
|
|
kExport: $ => /[eE][xX][pP][oO][rR][tT]/,
|
|
kFar: $ => /[fF][aA][rR]/,
|
|
kNear: $ => /[nN][eE][aA][rR]/,
|
|
kSafecall: $ => /[sS][aA][fF][eE][cC][aA][lL]/,
|
|
kAssembler: $ => /[aA][sS][sS][eE][mM][bB][lL][eE][rR]/,
|
|
kNostackframe: $ => /[nN][oO][sS][tT][aA][cC][kK][fF][rR][aA][mM][eE]/,
|
|
kInterrupt: $ => /[iI][nN][tT][eE][rR][rR][uU][pP][tT]/,
|
|
kNoreturn: $ => /[nN][oO][rR][eE][tT][uU][rR][nN]/,
|
|
kIocheck: $ => /[iI][oO][cC][hH][eE][cC][kK]/,
|
|
kLocal: $ => /[lL][oO][cC][aA][lL]/,
|
|
kHardfloat: $ => /[hH][aA][rR][dD][fF][lL][oO][aA][tT]/,
|
|
kSoftfloat: $ => /[sS][oO][fF][tT][fF][lL][oO][aA][tT]/,
|
|
kMs_abi_default: $ => /[mM][sS]_[aA][bB][iI]_[dD][eE][fF][aA][uU][lL][tT]/,
|
|
kMs_abi_cdecl: $ => /[mM][sS]_[aA][bB][iI]_[cC][dD][eE][cC][lL]/,
|
|
kSaveregisters: $ => /[sS][aA][vV][eE][rR][eE][gG][iI][sS][tT][eE][rR][sS]/,
|
|
kSysv_abi_default: $ => /[sS][yY][sS][vV]_[aA][bB][iI]_[dD][eE][fF][aA][uU][lL][tT]/,
|
|
kSysv_abi_cdecl: $ => /[sS][yY][sS][vV]_[aA][bB][iI]_[cC][dD][eE][cC][lL]/,
|
|
kVectorcall: $ => /[vV][eE][cC][tT][oO][rR][cC][aA][lL][lL]/,
|
|
kVarargs: $ => /[vV][aA][rR][aA][rR][gG][sS]/,
|
|
kWinapi: $ => /[wW][iI][nN][aA][pP][iI]/,
|
|
kAlias: $ => /[aA][lL][iI][aA][sS]/,
|
|
// Delphi
|
|
kDelayed: $ => /[dD][eE][lL][aA][yY][eE][dD]/,
|
|
|
|
kNil: $ => /[nN][iI][lL]/,
|
|
kTrue: $ => /[tT][rR][uU][eE]/,
|
|
kFalse: $ => /[fF][aA][lL][sS][eE]/,
|
|
|
|
kIfdef: $ => /[iI][fF][dD][eE][fF]/,
|
|
kIfndef: $ => /[iI][fF][nN][dD][eE][fF]/,
|
|
kEndif: $ => /[eE][nN][dD][iI][fF]/,
|
|
|
|
identifier: $ => /[&]?[a-zA-Z_]+[0-9_a-zA-Z]*/,
|
|
|
|
_space: $ => /[\s\r\n\t]+/,
|
|
pp: $ => /\{\$[^}]*\}/,
|
|
comment: $ => token(choice(
|
|
seq('//', /.*/),
|
|
seq('{', /([^$}][^}]*)?/, '}'),
|
|
seq(/[(][*]([^*]*[*]+[^)*])*[^*]*[*]+[)]/)
|
|
)),
|
|
}
|
|
});
|