mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 10:19:17 +00:00
99f0fb5b70
Fixes #49364 TEST=ci Change-Id: Ic643819c9cdd7b56690981b96b854b1e8d622fff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250160 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
550 lines
18 KiB
Dart
550 lines
18 KiB
Dart
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// IDL grammar variants.
|
|
const int WEBIDL_SYNTAX = 0;
|
|
const int WEBKIT_SYNTAX = 1;
|
|
const int FREMONTCUT_SYNTAX = 2;
|
|
|
|
/**
|
|
* IDLFile is the top-level node in each IDL file. It may contain modules or
|
|
* interfaces.
|
|
*/
|
|
class IDLFile extends IDLNode {
|
|
|
|
String filename;
|
|
List<IDLModule> modules;
|
|
List<IDLInterface> interfaces;
|
|
|
|
IDLFile(this.filename, this.modules, this.interfaces);
|
|
}
|
|
|
|
/**
|
|
* IDLModule has an id, and may contain interfaces, type defs and implements
|
|
* statements.
|
|
*/
|
|
class IDLModule extends IDLNode {
|
|
String id;
|
|
List interfaces;
|
|
List typedefs;
|
|
List implementsStatements;
|
|
|
|
IDLModule(String this.id, IDLExtAttrs extAttrs, IDLAnnotations annotations,
|
|
List<IDLNode> elements) {
|
|
setExtAttrs(extAttrs);
|
|
this.annotations = annotations;
|
|
this.interfaces = elements.where((e) => e is IDLInterface).toList();
|
|
this.typedefs = elements.where((e) => e is IDLTypeDef).toList();
|
|
this.implementsStatements =
|
|
elements.where((e) => e is IDLImplementsStatement).toList();
|
|
}
|
|
|
|
toString() => '<IDLModule $id $extAttrs $annotations>';
|
|
}
|
|
|
|
class IDLNode {
|
|
IDLExtAttrs extAttrs;
|
|
IDLAnnotations annotations;
|
|
IDLNode();
|
|
|
|
setExtAttrs(IDLExtAttrs ea) {
|
|
assert(ea != null);
|
|
this.extAttrs = ea != null ? ea : new IDLExtAttrs();
|
|
}
|
|
}
|
|
|
|
class IDLType extends IDLNode {
|
|
String id;
|
|
IDLType parameter;
|
|
bool nullable = false;
|
|
IDLType(String this.id, [IDLType this.parameter, bool this.nullable = false]);
|
|
|
|
// TODO: Figure out why this constructor was failing in mysterious ways.
|
|
// IDLType.nullable(IDLType base) {
|
|
// return new IDLType(base.id, base.parameter, true);
|
|
// }
|
|
|
|
//String toString() => '<IDLType $nullable $id $parameter>';
|
|
String toString() {
|
|
String nullableTag = nullable ? '?' : '';
|
|
return '<IDLType $id${parameter == null ? '' : ' $parameter'}$nullableTag>';
|
|
}
|
|
}
|
|
|
|
class IDLTypeDef extends IDLNode {
|
|
String id;
|
|
IDLType type;
|
|
IDLTypeDef(String this.id, IDLType this.type);
|
|
|
|
toString() => '<IDLTypeDef $id $type>';
|
|
}
|
|
|
|
class IDLImplementsStatement extends IDLNode {
|
|
}
|
|
|
|
class IDLInterface extends IDLNode {
|
|
String id;
|
|
List parents;
|
|
List operations;
|
|
List attributes;
|
|
List constants;
|
|
List snippets;
|
|
|
|
bool isSupplemental;
|
|
bool isNoInterfaceObject;
|
|
bool isFcSuppressed;
|
|
|
|
IDLInterface(String this.id, IDLExtAttrs ea, IDLAnnotations ann,
|
|
List this.parents, List members) {
|
|
setExtAttrs(ea);
|
|
this.annotations = ann;
|
|
if (this.parents == null) this.parents = [];
|
|
|
|
operations = members.where((e) => e is IDLOperation).toList();
|
|
attributes = members.where((e) => e is IDLAttribute).toList();
|
|
constants = members.where((e) => e is IDLConstant).toList();
|
|
snippets = members.where((e) => e is IDLSnippet).toList();
|
|
|
|
isSupplemental = extAttrs.has('Supplemental');
|
|
isNoInterfaceObject = extAttrs.has('NoInterfaceObject');
|
|
isFcSuppressed = extAttrs.has('Suppressed');
|
|
}
|
|
|
|
toString() => '<IDLInterface $id $extAttrs $annotations>';
|
|
}
|
|
|
|
class IDLMember extends IDLNode {
|
|
String id;
|
|
IDLType type;
|
|
bool isFcSuppressed;
|
|
|
|
IDLMember(String this.id, IDLType this.type, IDLExtAttrs ea, IDLAnnotations ann) {
|
|
setExtAttrs(ea);
|
|
this.annotations = ann;
|
|
|
|
isFcSuppressed = extAttrs.has('Suppressed');
|
|
}
|
|
}
|
|
|
|
class IDLOperation extends IDLMember {
|
|
List arguments;
|
|
|
|
// Ignore all forms of raises for now.
|
|
List specials;
|
|
bool isStringifier;
|
|
|
|
IDLOperation(String id, IDLType type, IDLExtAttrs ea, IDLAnnotations ann,
|
|
List this.arguments, List this.specials, bool this.isStringifier)
|
|
: super(id, type, ea, ann) {
|
|
}
|
|
|
|
toString() => '<IDLOperation $type $id ${printList(arguments)}>';
|
|
}
|
|
|
|
class IDLAttribute extends IDLMember {
|
|
}
|
|
|
|
class IDLConstant extends IDLMember {
|
|
var value;
|
|
IDLConstant(String id, IDLType type, IDLExtAttrs ea, IDLAnnotations ann,
|
|
var this.value)
|
|
: super(id, type, ea, ann);
|
|
}
|
|
|
|
class IDLSnippet extends IDLMember {
|
|
String text;
|
|
IDLSnippet(IDLAnnotations ann, String this.text)
|
|
: super(null, null, new IDLExtAttrs(), ann);
|
|
}
|
|
|
|
/** Maps string to something. */
|
|
class IDLDictNode {
|
|
Map<String, Object> map;
|
|
IDLDictNode() {
|
|
map = new Map<String, Object>();
|
|
}
|
|
|
|
setMap(List associationList) {
|
|
if (associationList == null) return;
|
|
for (var element in associationList) {
|
|
var name = element[0];
|
|
var value = element[1];
|
|
map[name] = value;
|
|
}
|
|
}
|
|
|
|
bool has(String key) => map.containsKey(key);
|
|
|
|
formatMap() {
|
|
if (map.isEmpty)
|
|
return '';
|
|
StringBuffer sb = new StringBuffer();
|
|
map.forEach((k, v) {
|
|
sb.add(' $k');
|
|
if (v != null) {
|
|
sb.add('=$v');
|
|
}
|
|
});
|
|
return sb.toString();
|
|
}
|
|
|
|
}
|
|
|
|
class IDLExtAttrs extends IDLDictNode {
|
|
IDLExtAttrs([List attrs = const []]) : super() {
|
|
setMap(attrs);
|
|
}
|
|
|
|
toString() => '<IDLExtAttrs${formatMap()}>';
|
|
}
|
|
|
|
class IDLArgument extends IDLNode {
|
|
String id;
|
|
IDLType type;
|
|
bool isOptional;
|
|
bool isIn;
|
|
bool hasEllipsis;
|
|
IDLArgument(String this.id, IDLType this.type, IDLExtAttrs extAttrs,
|
|
bool this.isOptional, bool this.isIn, bool this.hasEllipsis) {
|
|
setExtAttrs(extAttrs);
|
|
}
|
|
|
|
toString() => '<IDLArgument $id>';
|
|
}
|
|
|
|
class IDLAnnotations extends IDLDictNode {
|
|
IDLAnnotations(List annotations) : super() {
|
|
for (var annotation in annotations) {
|
|
map[annotation.id] = annotation;
|
|
}
|
|
}
|
|
|
|
toString() => '<IDLAnnotations${formatMap()}>';
|
|
}
|
|
|
|
class IDLAnnotation extends IDLDictNode {
|
|
String id;
|
|
IDLAnnotation(String this.id, List args) : super() {
|
|
setMap(args);
|
|
}
|
|
|
|
toString() => '<IDLAnnotation $id${formatMap()}>';
|
|
}
|
|
|
|
class IDLExtAttrFunctionValue extends IDLNode {
|
|
String name;
|
|
List arguments;
|
|
IDLExtAttrFunctionValue(String this.name, this.arguments);
|
|
|
|
toString() => '<IDLExtAttrFunctionValue $name(${arguments.length})>';
|
|
}
|
|
|
|
class IDLParentInterface extends IDLNode {}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class IDLParser {
|
|
final int syntax;
|
|
Grammar grammar;
|
|
var axiom;
|
|
|
|
IDLParser([syntax=WEBIDL_SYNTAX]) : syntax = syntax {
|
|
grammar = new Grammar();
|
|
axiom = _makeParser();
|
|
}
|
|
|
|
syntax_switch([WebIDL, WebKit, FremontCut]) {
|
|
assert(WebIDL != null && WebKit != null); // Not options, just want names.
|
|
if (syntax == WEBIDL_SYNTAX)
|
|
return WebIDL;
|
|
if (syntax == WEBKIT_SYNTAX)
|
|
return WebKit;
|
|
if (syntax == FREMONTCUT_SYNTAX)
|
|
return FremontCut == null ? WebIDL : FremontCut;
|
|
throw new Exception('unsupported IDL syntax $syntax');
|
|
}
|
|
|
|
_makeParser() {
|
|
Grammar g = grammar;
|
|
|
|
// TODO: move syntax_switch back to here.
|
|
|
|
var idStartCharSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_';
|
|
var idNextCharSet = idStartCharSet + '0123456789';
|
|
var hexCharSet = '0123456789ABCDEFabcdef';
|
|
|
|
var idStartChar = CHAR(idStartCharSet);
|
|
var idNextChar = CHAR(idNextCharSet);
|
|
|
|
var digit = CHAR('0123456789');
|
|
|
|
var Id = TEXT(LEX('an identifier',[idStartChar, MANY(idNextChar, min:0)]));
|
|
|
|
var IN = SKIP(LEX("'in'", ['in',NOT(idNextChar)]));
|
|
|
|
var BooleanLiteral = OR(['true', 'false']);
|
|
var IntegerLiteral = TEXT(LEX('hex-literal', OR([['0x', MANY(CHAR(hexCharSet))],
|
|
[MANY(digit)]])));
|
|
var FloatLiteral = TEXT(LEX('float-literal', [MANY(digit), '.', MANY(digit, min:0)]));
|
|
|
|
|
|
var Argument = g['Argument'];
|
|
var Module = g['Module'];
|
|
var Member = g['Member'];
|
|
var Interface = g['Interface'];
|
|
var ExceptionDef = g['ExceptionDef'];
|
|
var Type = g['Type'];
|
|
var TypeDef = g['TypeDef'];
|
|
var ImplStmt = g['ImplStmt'];
|
|
var ValueTypeDef = g['ValueTypeDef'];
|
|
var Const = g['Const'];
|
|
var Attribute = g['Attribute'];
|
|
var Operation = g['Operation'];
|
|
var Snippet = g['Snippet'];
|
|
var ExtAttrs = g['ExtAttrs'];
|
|
var MaybeExtAttrs = g['MaybeExtAttrs'];
|
|
var MaybeAnnotations = g['MaybeAnnotations'];
|
|
var ParentInterfaces = g['ParentInterfaces'];
|
|
|
|
|
|
final ScopedName = TEXT(LEX('scoped-name', MANY(CHAR(idStartCharSet + '_:.<>'))));
|
|
|
|
final ScopedNames = MANY(ScopedName, separator:',');
|
|
|
|
// Types
|
|
|
|
final IntegerTypeName = OR([
|
|
['byte', () => 'byte'],
|
|
['int', () => 'int'],
|
|
['long', 'long', () => 'long long'],
|
|
['long', () => 'long'],
|
|
['octet', () => 'octet'],
|
|
['short', () => 'short']]);
|
|
|
|
final IntegerType = OR([
|
|
['unsigned', IntegerTypeName, (name) => new IDLType('unsigned $name')],
|
|
[IntegerTypeName, (name) => new IDLType(name)]]);
|
|
|
|
final BooleanType = ['boolean', () => new IDLType('boolean')];
|
|
final OctetType = ['octet', () => new IDLType('octet')];
|
|
final FloatType = ['float', () => new IDLType('float')];
|
|
final DoubleType = ['double', () => new IDLType('double')];
|
|
|
|
final SequenceType = ['sequence', '<', Type, '>',
|
|
(type) => new IDLType('sequence', type)];
|
|
|
|
final ScopedNameType = [ScopedName, (name) => new IDLType(name)];
|
|
|
|
final NullableType =
|
|
[OR([IntegerType, BooleanType, OctetType, FloatType,
|
|
DoubleType, SequenceType, ScopedNameType]),
|
|
MAYBE('?'),
|
|
(type, nullable) =>
|
|
nullable ? new IDLType(type.id, type.parameter, true) : type];
|
|
|
|
final VoidType = ['void', () => new IDLType('void')];
|
|
final AnyType = ['any', () => new IDLType('any')];
|
|
final ObjectType = ['object', () => new IDLType('object')];
|
|
|
|
Type.def = OR([AnyType, ObjectType, NullableType]);
|
|
|
|
final ReturnType = OR([VoidType, Type]);
|
|
|
|
var Definition = syntax_switch(
|
|
WebIDL: OR([Module, Interface, ExceptionDef, TypeDef, ImplStmt,
|
|
ValueTypeDef, Const]),
|
|
WebKit: OR([Module, Interface]));
|
|
|
|
var Definitions = MANY(Definition, min:0);
|
|
|
|
Module.def = syntax_switch(
|
|
WebIDL: [MaybeExtAttrs, 'module', Id, '{', Definitions, '}',
|
|
SKIP(MAYBE(';')),
|
|
(ea, id, defs) => new IDLModule(id, ea, null, defs)],
|
|
WebKit: ['module', MaybeExtAttrs, Id, '{', Definitions, '}',
|
|
SKIP(MAYBE(';')),
|
|
(ea, id, defs) => new IDLModule(id, ea, null, defs)],
|
|
FremontCut: [MaybeAnnotations, MaybeExtAttrs, 'module', Id,
|
|
'{', Definitions, '}', SKIP(MAYBE(';')),
|
|
(ann, ea, id, defs) => new IDLModule(id, ea, ann, defs)]);
|
|
|
|
Interface.def = syntax_switch(
|
|
WebIDL: [MaybeExtAttrs, 'interface', Id, MAYBE(ParentInterfaces),
|
|
MAYBE(['{', MANY0(Member), '}']), ';',
|
|
(ea, id, p, ms) => new IDLInterface(id, ea, null, p, ms)],
|
|
WebKit: ['interface', MaybeExtAttrs, Id, MAYBE(ParentInterfaces),
|
|
MAYBE(['{', MANY0(Member), '}']), ';',
|
|
(ea, id, p, ms) => new IDLInterface(id, ea, null, p, ms)],
|
|
FremontCut: [MaybeAnnotations, MaybeExtAttrs, 'interface',
|
|
Id, MAYBE(ParentInterfaces),
|
|
MAYBE(['{', MANY0(Member), '}']), ';',
|
|
(ann, ea, id, p, ms) => new IDLInterface(id, ea, ann, p, ms)]);
|
|
|
|
Member.def = syntax_switch(
|
|
WebIDL: OR([Const, Attribute, Operation, ExtAttrs]),
|
|
WebKit: OR([Const, Attribute, Operation]),
|
|
FremontCut: OR([Const, Attribute, Operation, Snippet]));
|
|
|
|
var InterfaceType = ScopedName;
|
|
|
|
var ParentInterface = syntax_switch(
|
|
WebIDL: [InterfaceType],
|
|
WebKit: [InterfaceType],
|
|
FremontCut: [MaybeAnnotations, InterfaceType]);
|
|
|
|
ParentInterfaces.def = [':', MANY(ParentInterface, ',')];
|
|
|
|
// TypeDef (Web IDL):
|
|
TypeDef.def = ['typedef', Type, Id, ';', (type, id) => new IDLTypeDef(id, type)];
|
|
|
|
// TypeDef (Old-school W3C IDLs)
|
|
ValueTypeDef.def = ['valuetype', Id, Type, ';'];
|
|
|
|
// Implements Statement (Web IDL):
|
|
var ImplStmtImplementor = ScopedName;
|
|
var ImplStmtImplemented = ScopedName;
|
|
|
|
ImplStmt.def = [ImplStmtImplementor, 'implements', ImplStmtImplemented, ';'];
|
|
|
|
var ConstExpr = OR([BooleanLiteral, IntegerLiteral, FloatLiteral]);
|
|
|
|
Const.def = syntax_switch(
|
|
WebIDL: [MaybeExtAttrs, 'const', Type, Id, '=', ConstExpr, ';',
|
|
(ea, type, id, v) => new IDLConstant(id, type, ea, null, v)],
|
|
WebKit: ['const', MaybeExtAttrs, Type, Id, '=', ConstExpr, ';',
|
|
(ea, type, id, v) => new IDLConstant(id, type, ea, null, v)],
|
|
FremontCut: [MaybeAnnotations, MaybeExtAttrs,
|
|
'const', Type, Id, '=', ConstExpr, ';',
|
|
(ann, ea, type, id, v) =>
|
|
new IDLConstant(id, type, ea, ann, v)]);
|
|
|
|
// Attributes
|
|
|
|
var Stringifier = 'stringifier';
|
|
var AttrGetter = 'getter';
|
|
var AttrSetter = 'setter';
|
|
var ReadOnly = 'readonly';
|
|
var AttrGetterSetter = OR([AttrGetter, AttrSetter]);
|
|
|
|
var GetRaises = syntax_switch(
|
|
WebIDL: ['getraises', '(', ScopedNames, ')'],
|
|
WebKit: ['getter', 'raises', '(', ScopedNames, ')']);
|
|
|
|
var SetRaises = syntax_switch(
|
|
WebIDL: ['setraises', '(', ScopedNames, ')'],
|
|
WebKit: ['setter', 'raises', '(', ScopedNames, ')']);
|
|
|
|
var Raises = ['raises', '(', ScopedNames, ')'];
|
|
|
|
var AttrRaises = syntax_switch(
|
|
WebIDL: MANY(OR([GetRaises, SetRaises])),
|
|
WebKit: MANY(OR([GetRaises, SetRaises, Raises]), separator:','));
|
|
|
|
Attribute.def = syntax_switch(
|
|
WebIDL: [MaybeExtAttrs, MAYBE(Stringifier), MAYBE(ReadOnly),
|
|
'attribute', Type, Id, MAYBE(AttrRaises), ';'],
|
|
WebKit: [MAYBE(Stringifier), MAYBE(ReadOnly), 'attribute',
|
|
MaybeExtAttrs, Type, Id, MAYBE(AttrRaises), ';'],
|
|
FremontCut: [MaybeAnnotations, MaybeExtAttrs,
|
|
MAYBE(AttrGetterSetter), MAYBE(Stringifier), MAYBE(ReadOnly),
|
|
'attribute', Type, Id, MAYBE(AttrRaises), ';'
|
|
]);
|
|
|
|
// Operations
|
|
|
|
final Special = TEXT(OR(['getter', 'setter', 'creator', 'deleter', 'caller']));
|
|
final Specials = MANY(Special);
|
|
|
|
final Optional = 'optional';
|
|
final AnEllipsis = '...';
|
|
|
|
Argument.def = syntax_switch(
|
|
WebIDL: SEQ(MaybeExtAttrs, MAYBE(Optional), MAYBE(IN),
|
|
MAYBE(Optional), Type, MAYBE(AnEllipsis), Id,
|
|
(e, opt1, isin, opt2, type, el, id) =>
|
|
new IDLArgument(id, type, e, opt1 || opt2, isin, el)),
|
|
|
|
WebKit: SEQ(MAYBE(Optional), MAYBE('in'), MAYBE(Optional),
|
|
MaybeExtAttrs, Type, Id
|
|
(opt1, isin, opt2, e, type, id) =>
|
|
new IDLArgument(id, type, e, opt1 || opt2, isin, false)));
|
|
|
|
final Arguments = MANY0(Argument, ',');
|
|
|
|
Operation.def = syntax_switch(
|
|
WebIDL: [MaybeExtAttrs, MAYBE(Stringifier), MAYBE(Specials),
|
|
ReturnType, MAYBE(Id), '(', Arguments, ')', MAYBE(Raises), ';',
|
|
(ea, isStringifier, specials, type, id, args, raises) =>
|
|
new IDLOperation(id, type, ea, null, args, specials, isStringifier)
|
|
],
|
|
WebKit: [MaybeExtAttrs, ReturnType, MAYBE(Id), '(', Arguments, ')',
|
|
MAYBE(Raises), ';',
|
|
(ea, type, id, args, raises) =>
|
|
new IDLOperation(id, type, ea, null, args, [], false)
|
|
],
|
|
FremontCut: [MaybeAnnotations, MaybeExtAttrs, MAYBE(Stringifier),
|
|
MAYBE(Specials), ReturnType, MAYBE(Id), '(', Arguments, ')',
|
|
MAYBE(Raises), ';',
|
|
(ann, ea, isStringifier, specials, type, id, args, raises) =>
|
|
new IDLOperation(id, type, ea, ann, args, specials, isStringifier)
|
|
]);
|
|
|
|
// Exceptions
|
|
|
|
final ExceptionField = [Type, Id, ';'];
|
|
final ExceptionMember = OR([Const, ExceptionField, ExtAttrs]);
|
|
ExceptionDef.def = ['exception', Id, '{', MANY0(ExceptionMember), '}', ';'];
|
|
|
|
// ExtendedAttributes
|
|
|
|
var ExtAttrArgList = ['(', MANY0(Argument, ','), ')'];
|
|
|
|
var ExtAttrFunctionValue =
|
|
[Id, '(', MANY0(Argument, ','), ')',
|
|
(name, args) => new IDLExtAttrFunctionValue(name, args)
|
|
];
|
|
|
|
var ExtAttrValue = OR([ExtAttrFunctionValue,
|
|
TEXT(LEX('value', MANY(CHAR(idNextCharSet + '&:-|'))))]);
|
|
|
|
var ExtAttr = [Id, MAYBE(OR([['=', ExtAttrValue], ExtAttrArgList]))];
|
|
|
|
ExtAttrs.def = ['[', MANY(ExtAttr, ','), ']',
|
|
(list) => new IDLExtAttrs(list)];;
|
|
|
|
MaybeExtAttrs.def = OR(ExtAttrs,
|
|
[ () => new IDLExtAttrs() ] );
|
|
|
|
// Annotations - used in the FremontCut IDL grammar.
|
|
|
|
var AnnotationArgValue = TEXT(LEX('xx', MANY(CHAR(idNextCharSet + '&:-|'))));
|
|
|
|
var AnnotationArg = [Id, MAYBE(['=', AnnotationArgValue])];
|
|
|
|
var AnnotationBody = ['(', MANY0(AnnotationArg, ','), ')'];
|
|
|
|
var Annotation = ['@', Id, MAYBE(AnnotationBody),
|
|
(id, body) => new IDLAnnotation(id, body)];
|
|
|
|
MaybeAnnotations.def = [MANY0(Annotation), (list) => new IDLAnnotations(list)];
|
|
|
|
// Snippets - used in the FremontCut IDL grammar.
|
|
|
|
final SnippetText = TEXT(LEX('snippet body', MANY0([NOT('}'), CHAR()])));
|
|
Snippet.def = [MaybeAnnotations, 'snippet', '{', SnippetText, '}', ';',
|
|
(ann, text) => new IDLSnippet(ann, text)];
|
|
|
|
|
|
grammar.whitespace =
|
|
OR([MANY(CHAR(' \t\r\n')),
|
|
['//', MANY0([NOT(CHAR('\r\n')), CHAR()])],
|
|
['#', MANY0([NOT(CHAR('\r\n')), CHAR()])],
|
|
['/*', MANY0([NOT('*/'), CHAR()]), '*/']]);
|
|
|
|
// Top level - at least one definition.
|
|
return MANY(Definition);
|
|
|
|
}
|
|
}
|