Remove code which no longer compiles.

Probably hasn't worked in a while, so it's unlikely
that anything depends on it.

Change-Id: I7b73b92842b897b8367bf48a490a0e25cd306b3f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292083
Reviewed-by: Srujan Gaddam <srujzs@google.com>
Auto-Submit: Lasse Nielsen <lrn@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Lasse Nielsen <lrn@google.com>
This commit is contained in:
Lasse R.H. Nielsen 2023-04-03 23:40:05 +00:00 committed by Commit Queue
parent 4cb8bd0c37
commit 0386350aa7
6 changed files with 0 additions and 2158 deletions

View file

@ -1,549 +0,0 @@
// 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);
}
}

View file

@ -1,120 +0,0 @@
// 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.
library idlparser_test;
import '../../../utils/peg/pegparser.dart';
part 'idlparser.dart';
part 'idlrenderer.dart';
main() {
IDLParser parser = new IDLParser(FREMONTCUT_SYNTAX);
Grammar g = parser.grammar;
var Type = g['Type'];
show(g, Type, 'int');
show(g, Type, 'int ?');
show(g, Type, 'sequence<int?> ?');
show(g, Type, 'unsigned long long?');
show(g, Type, 'unsignedlonglong?');
var MaybeAnnotations = g['MaybeAnnotations'];
show(g, MaybeAnnotations, '');
show(g, MaybeAnnotations, '@Foo');
show(g, MaybeAnnotations, '@Foo @Bar');
show(g, MaybeAnnotations, '@Foo(A,B=1) @Bar');
var MaybeExtAttrs = g['MaybeExtAttrs'];
print(MaybeExtAttrs);
show(g, MaybeExtAttrs, '');
show(g, MaybeExtAttrs, '[A]');
var Module = g['Module'];
show(g, Module, 'module Harry { const int bob = 30;};');
show(g, Module, """
module Harry { [X,Y,Z=99] const int bob = 30; typedef x y;
interface Thing : SuperA, @Friendly SuperB {
[Nice] const unsigned long long kFoo = 12345;
[A,B,C,D,E] attribute int attr1;
[F=f(int a),K=99,DartName=Bert] int smudge(int a, int b, double x);
[X,Y,Z] int xyz([U,V] optional in optional int z);
[P,Q,R] int pqr();
int op1();
@Smurf @Beans(B=1,C,A=2) int op2();
snippet { yadda
yadda
};
};
//[A] const unsigned long long dweeb = 0xff;
};
""");
}
show(grammar, rule, input) {
print('show: "$input"');
var ast;
try {
ast = grammar.parse(rule, input);
} catch (exception) {
if (exception is ParseError)
ast = exception;
else
throw;
}
print('${printList(ast)}');
print(render(ast));
}
void check(grammar, rule, input, expected) {
// If [expected] is String then the result is coerced to string.
// If [expected] is !String, the result is compared directly.
print('check: "$input"');
var ast;
try {
ast = grammar.parse(rule, input);
} catch (exception) {
ast = exception;
}
var formatted = ast;
if (expected is String)
formatted = printList(ast);
if (expected != formatted) {
throw new StateError("parse: $input");
}
}
// Prints the list in [1,2,3] notation, including nested lists.
void printList(item) {
if (item is List) {
StringBuffer sb = new StringBuffer();
sb.add('[');
var sep = '';
for (var x in item) {
sb.add(sep);
sb.add(printList(x));
sep = ',';
}
sb.add(']');
return sb.toString();
}
if (item == null)
return 'null';
return item.toString();
}

View file

@ -1,178 +0,0 @@
// 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.
List sorted(Iterable input, [compare, key]) {
comparator(compare, key) {
if (compare == null && key == null) return (a, b) => a.compareTo(b);
if (compare == null) return (a, b) => key(a).compareTo(key(b));
if (key == null) return compare;
return (a, b) => compare(key(a), key(b));
}
List copy = new List.from(input);
copy.sort(comparator(compare, key));
return copy;
}
render(idl_node, [indent_str = ' ']) {
var output = [''];
var indent_stack = [];
// TODO: revert to indented(action()) {
indented(action) {
indent_stack.add(indent_str);
action();
indent_stack.removeLast();
}
sort(nodes) => sorted(nodes, key: (a) => a.id);
var w; // For some reason mutually recursive local functions don't work.
wln([node]) {
w(node);
output.add('\n');
}
w = (node, [list_separator]) {
/*
Writes the given node.
Args:
node -- a string, IDLNode instance or a list of such.
list_separator -- if provided, and node is a list,
list_separator will be written between the list items.
*/
if (node == null) {
return;
} else if (node is String) {
if (output.last.endsWith('\n')) output.addAll(indent_stack);
output.add(node);
} else if (node is List) {
var separator = null;
for (var element in node) {
w(separator);
separator = list_separator;
w(element);
}
} else if (node is IDLFile) {
w(node.modules);
w(node.interfaces);
} else if (node is IDLModule) {
w(node.annotations);
w(node.extAttrs);
wln('module ${node.id} {');
indented(() {
w(node.interfaces);
w(node.typedefs);
});
wln('};');
} else if (node is IDLInterface) {
w(node.annotations);
w(node.extAttrs);
w('interface ${node.id}');
indented(() {
if (!node.parents.isEmpty) {
wln(' :');
w(node.parents, ',\n');
}
wln(' {');
section(list, comment) {
if (list != null && !list.isEmpty) {
wln();
wln(comment);
w(sort(list));
}
}
section(node.constants, '/* Constants */');
section(node.attributes, '/* Attributes */');
section(node.operations, '/* Operations */');
section(node.snippets, '/* Snippets */');
});
wln('};');
} else if (node is IDLParentInterface) {
w(node.annotations);
w(node.type.id);
} else if (node is IDLAnnotations) {
for (var name in sorted(node.map.keys)) {
IDLAnnotation annotation = node.map[name];
var args = annotation.map;
if (args.isEmpty) {
w('@$name');
} else {
var formattedArgs = [];
for (var argName in sorted(args.keys)) {
var argValue = args[argName];
if (argValue == null)
formattedArgs.add(argName);
else
formattedArgs.add('$argName=$argValue');
}
w('@$name(${formattedArgs.join(',')})');
}
w(' ');
}
} else if (node is IDLExtAttrs) {
if (!node.map.isEmpty) {
w('[');
var sep = null;
for (var name in sorted(node.map.keys)) {
w(sep);
sep = ', ';
w(name);
var value = node.map[name];
if (value != null) {
w('=');
w(value);
}
}
w('] ');
}
} else if (node is IDLAttribute) {
w(node.annotations);
w(node.extAttrs);
//if (node.isFcGetter)
// w('getter ');
//if (node.isFcSetter)
// w('setter ');
wln('attribute ${node.type.id} ${node.id};');
} else if (node is IDLConstant) {
w(node.annotations);
w(node.extAttrs);
wln('const ${node.type.id} ${node.id} = ${node.value};');
} else if (node is IDLSnippet) {
w(node.annotations);
wln('snippet {${node.text}};');
} else if (node is IDLOperation) {
w(node.annotations);
w(node.extAttrs);
if (node.specials != null && !node.specials.isEmpty) {
w(node.specials, ' ');
w(' ');
}
w('${node.type.id} ${node.id}');
w('(');
w(node.arguments, ', ');
wln(');');
} else if (node is IDLArgument) {
w(node.extAttrs);
w('in ');
if (node.isOptional) w('optional ');
w('${node.type.id} ${node.id}');
} else if (node is IDLExtAttrFunctionValue) {
w(node.name);
w('(');
w(node.arguments, ', ');
w(')');
} else if (node is IDLTypeDef) {
wln('typedef ${node.type.id} ${node.id};');
} else {
w('// $node\n');
}
};
w(idl_node);
return output.join();
}

View file

@ -1,888 +0,0 @@
// 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.
library PegParser;
/*
* The following functions are combinators for building Rules.
*
* A rule is one of the following
* - A String which matches the string literally.
* - A Symbol which matches the symbol's definition.
* - A list of rules with an optional reducing function, which matches a sequence.
* - The result of calling one of the combinators.
*
* Some rules are 'value-generating' rules, they return an 'abstract syntax
* tree' with the match. If a rule is not value-generating [:null:] is the
* value.
*
* A Symbol is always a value-generating rule. If the value is not required, use
* [:SKIP(aSymbol):] in place of [:aSymbol:].
*
* A String is not a value-generating rule but can be converted into one by
* using [:TEXT('string'):] in place of [:'string':].
*
* A list or sequence is value-generating depending on the subrules. The
* sequence is value-generating if any of the subrules are value-generating or
* if there is a reducing function. If no reducing function is given, the value
* returned depends on the number of value-generating subrules. If there is
* only one value generating subrule, that provides the value for the sequence.
* If there are more, then the value is a list of the values of the
* value-generating subrules.
*/
/**
* Matches one character by a predicate on the character code.
* If [spec] is an int, that character is matched.
* If [spec] is a function it is used
*
* Example [: CHARCODE((code) => 48 <= code && code <= 57) :] recognizes an
* ASCII digit.
*
* CHARCODE does not generate a value.
*/
_Rule CHARCODE(spec, [name]) {
if (spec is int)
return new _CharCodeRule((code) => code == spec, name);
else
return new _CharCodeRule(spec, name);
}
/**
* Matches one of the [characters].
*
* CHAR does not generate a value.
*/
_Rule CHAR([characters]) {
if (characters == null) return const _AnyCharRule();
if (characters is int) return CHARCODE(characters);
// Find the range of character codes and construct an array of flags for codes
// within the range.
List<int> codes = characters.codeUnits.toList();
codes.sort((a, b) => a < b
? -1
: a > b
? 1
: 0);
int lo = codes[0];
int hi = codes[codes.length - 1];
if (lo == hi) return CHARCODE(lo);
int len = hi - lo + 1;
var flags = List<bool>.filled(len, false);
for (int code in codes) flags[code - lo] = true;
return CHARCODE((code) => code >= lo && code <= hi && flags[code - lo]);
}
/**
* Matches the end of the input.
*
* END does not generate a value.
*/
_Rule get END => new _EndOfInputRule();
/**
* Throws an exception.
*/
_Rule ERROR(String message) => new _ErrorRule(message);
/**
* Matches [rule] but does not consume the input. Useful for matching a right
* context.
*
* AT does not generate a value.
*/
_Rule AT(rule) => new _ContextRule(_compile(rule));
/**
* Matches when [rule] does not match. No input is consumed.
*
* NOT does not generate a value.
*/
_Rule NOT(rule) => new _NegativeContextRule(_compile(rule));
/**
* Matches [rule] but generates no value even if [rule] generates a value.
*
* SKIP never generates a value.
*/
_Rule SKIP(rule) => new _SkipRule(_compile(rule));
/**
* Matches [rule] in a lexical context where whitespace is not automatically
* skipped. Useful for matching what would normally be considered to be tokens.
* [name] is a user-friendly description of what is being matched and is used in
* error messages.
*
* LEX(rule)
* LEX(name, rule)
*
* LEX does not generate a value. If a value is required, wrap LEX with TEXT.
*/
_Rule LEX(arg1, [arg2]) {
if (arg2 == null)
return new _LexicalRule(arg1 is String ? arg1 : null, _compile(arg1));
else
return new _LexicalRule(arg1, _compile(arg2));
}
/**
* Matches [rule] and generates a value from the matched text. If the [rule]
* matches, then TEXT(rule) matches and has a value derived from the string
* fragment that was matched. The default derived value is the string fragment.
*
* TEXT always generates a value.
*/
_Rule TEXT(rule, [extractor]) => new _TextValueRule(
_compile(rule),
extractor == null
? (string, start, end) => string.substring(start, end)
: extractor);
/**
* Matches an optional rule.
*
* MAYBE is a value generating matcher.
*
* If [rule] is value generating then the value is the value generated by [rule]
* if it matches, and [:null:] if it does not.
*
* If [rule] is not value generating then the value is [:true:] if [rule]
* matches and [:false:] if it does not.
*/
_Rule MAYBE(rule) => new _OptionalRule(_compile(rule));
/**
* MANY(rule) matches [rule] [min] or more times.
* [min] must be 0 or 1.
* If [separator] is provided it is used to match a separator between matches of
* [rule].
*
* MANY is a value generating matcher. The value is a list of the matches of
* [rule]. The list may be empty if [:min == 0:].
*/
_Rule MANY(rule, {separator = null, int min = 1}) {
assert(0 <= min && min <= 1);
return new _RepeatRule(_compile(rule), _compileOptional(separator), min);
}
/**
* Matches [rule] zero or more times. Shorthand for [:MANY(rule, min:0):]
* TODO: retire min: parameter?
*
* MANY0 is a value generating matcher.
*/
_Rule MANY0(rule, [separator = null]) {
return new _RepeatRule(_compile(rule), _compileOptional(separator), 0);
}
/**
* Matches [rules] in order until one succeeds.
*
* OR is value-generating.
*/
_Rule OR(
[a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
l,
m,
n,
o,
p,
q,
r,
s,
t,
u,
v,
w,
x,
y,
z]) =>
_compileMultiRule(
(a is List && b == null) // Backward compat. OR([a, b]) => OR(a, b).
? a
: _unspread(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s,
t, u, v, w, x, y, z),
false,
(compiledRules, valueCount, reducer) => new _ChoiceRule(compiledRules));
_Rule SEQ(
[a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
l,
m,
n,
o,
p,
q,
r,
s,
t,
u,
v,
w,
x,
y,
z]) =>
_compile(_unspread(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s,
t, u, v, w, x, y, z));
/**
* Matches [rule]
*/
_Rule MEMO(rule) => new _MemoRule(_compile(rule));
_Rule TAG(tag, rule) => _compile([
rule,
(ast) => [tag, ast]
]);
class ParseError implements Exception {
const ParseError(String this._message);
String toString() => _message;
final String _message;
}
/**
* A grammar is a collection of symbols and rules that may be used to parse an
* input.
*/
class Grammar {
Map<String, Symbol> _symbols;
/** This rule may be set by the user to define whitespace. */
late _Rule _whitespace;
_Rule get whitespace => _whitespace;
void set whitespace(rule) {
_whitespace = _compile(rule);
}
Grammar() : _symbols = new Map<String, Symbol>() {
whitespace = CHAR(' \t\r\n');
}
/**
* operator [] is used to find or create symbols. Symbols may appear in rules
* to define recursive rules.
*/
Symbol operator [](String name) {
if (_symbols.containsKey(name)) return _symbols[name]!;
Symbol s = new Symbol(name, this);
_symbols[name] = s;
return s;
}
/**
* Parses the input string and returns the parsed AST, or throws an exception
* if the input can't be parsed.
*/
parse(root, String text) {
for (var symbol in _symbols.values)
if (symbol._rule == null) print('${symbol.name} is undefined');
var state = new _ParserState(text, whitespace: whitespace);
var match = _compile(root).match(state, 0);
if (match == null) return diagnose(state);
var pos = match[0];
pos = _skip_whitespace(state, pos);
if (pos == state._end) return match[1];
// TODO: Make this complain about expecting end of file.
return diagnose(state);
}
diagnose(state) {
var message = 'unexpected error';
if (!state.max_rule.isEmpty) {
var s = new Set();
for (var rule in state.max_rule) s.add(rule.description());
var tokens = new List<String>.from(s);
tokens.sort((a, b) => a.startsWith("'") == b.startsWith("'")
? a.compareTo(b)
: a.startsWith("'")
? 1
: -1);
var expected = tokens.join(' or ');
var found = state.max_pos == state._end
? 'end of file'
: "'${state._text[state.max_pos]}'";
message = 'Expected $expected but found $found';
}
int start = state.max_pos;
int end = start;
while (start >= 1 && state._text[start - 1] != '\n') --start;
while (end < state._text.length && state._text[end] != '\n') ++end;
var line = state._text.substring(start, end);
var indicator = '';
for (var i = 0; i < line.length && start + i < state.max_pos; i++)
indicator = ' $indicator';
indicator = '$indicator^';
// TODO: Convert to an exception.
print(message);
print(line);
print(indicator);
return null;
}
}
class Symbol {
final String name;
final Grammar grammar;
_Rule? _rule;
Symbol(this.name, this.grammar);
void set def(rule) {
assert(_rule == null); // Assign once.
_rule = _compile(rule);
}
toString() => _rule == null ? '<$name>' : '<$name = $_rule>';
}
class _ParserState {
_ParserState(this._text, {required _Rule whitespace})
: _end = _text.length,
whitespaceRule = whitespace {
max_rule = [];
}
String _text;
int _end;
//
bool inWhitespaceMode = false;
_Rule whitespaceRule;
// Used for constructing an error message.
int inhibitExpectedTrackingDepth = 0;
int max_pos = 0;
var max_rule;
}
/**
* An interface tag for rules. If this tag is on a rule, then the description()
* of the rule is something sensible to put in a message.
*/
abstract class _Expectable {
String description();
}
class _Rule {
const _Rule();
// Returns null for a match failure or [pos, ast] for success.
match(_ParserState state, int pos) {
if (!state.inWhitespaceMode) {
pos = _skip_whitespace(state, pos);
}
return matchAfterWS(state, pos);
}
// Faster entry point for matching a sub-rule that is matched to the start
// position of the super-rule. Whitespace has already been skipped so no need
// to try to skip it again.
matchAfterWS(_ParserState state, int pos) {
if (state.inhibitExpectedTrackingDepth == 0) {
// Track position for possible error messaging
if (pos > state.max_pos) {
// Store position and the rule.
state.max_pos = pos;
if (this is _Expectable) {
state.max_rule = [this];
} else {
state.max_rule = [];
}
} else if (pos == state.max_pos) {
if (this is _Expectable) {
state.max_rule.add(this);
}
}
}
// Delegate the matching logic to the specialized function.
return _match(state, pos);
}
// Overridden in subclasses to match the rule.
_match(_ParserState state, int pos) => null;
// Does the rule generate a value (AST) with the match?
bool get generatesValue => false;
get defaultValue => null;
}
int _skip_whitespace(state, pos) {
// Returns the next non-whitespace position.
// This is done by matching the optional whitespaceRule with the current text.
if (state.whitespaceRule == null) return pos;
state.inWhitespaceMode = true;
state.inhibitExpectedTrackingDepth++;
while (true) {
var match = state.whitespaceRule.match(state, pos);
if (match == null) break;
pos = match[0];
}
state.inWhitespaceMode = false;
state.inhibitExpectedTrackingDepth--;
return pos;
}
_Rule? _compileOptional(rule) {
return rule == null ? null : _compile(rule);
}
_Rule _compile(rule) {
if (rule is _Rule) return rule;
if (rule is String) return new _StringRule(rule);
if (rule is Symbol) return new _SymbolRule(rule);
if (rule is RegExp) return new _RegExpRule(rule);
if (rule is List) {
return _compileMultiRule(
rule,
true,
(compiledRules, valueCount, reducer) =>
new _SequenceRule(compiledRules, valueCount, reducer));
}
throw new Exception('Cannot compile rule: $rule');
}
class _EndOfInputRule extends _Rule {
_match(_ParserState state, int pos) {
if (pos == state._end) return [pos, null];
return null;
}
toString() => 'END';
}
class _ErrorRule extends _Rule {
String message;
_ErrorRule(String this.message);
_match(_ParserState state, int pos) {
throw new ParseError(message);
}
toString() => 'ERROR($message)';
}
class _CharCodeRule extends _Rule {
Function _predicate;
var _name;
_CharCodeRule(this._predicate, this._name);
_match(_ParserState state, int pos) {
if (pos == state._end) return null;
int code = state._text.codeUnitAt(pos);
if (_predicate(code)) return [pos + 1, null];
return null;
}
toString() => _name == null ? 'CHARCODE($_predicate)' : 'CHARCODE($_name)';
}
class _AnyCharRule extends _Rule {
const _AnyCharRule();
_match(_ParserState state, int pos) {
if (pos == state._end) return null;
return [pos + 1, null];
}
toString() => 'CHAR()';
}
class _SymbolRule extends _Rule {
final Symbol _symbol;
_SymbolRule(Symbol this._symbol);
_match(_ParserState state, int pos) {
if (_symbol._rule == null)
throw new Exception("Symbol '${_symbol.name}' is undefined");
return _symbol._rule!.match(state, pos);
}
bool get generatesValue => true;
toString() => '<${_symbol.name}>';
}
class _SkipRule extends _Rule {
// A rule that has no value.
_Rule _rule;
_SkipRule(_Rule this._rule);
_match(_ParserState state, int pos) {
var match = _rule.matchAfterWS(state, pos);
if (match == null) return null;
return [match[0], null];
}
toString() => 'TOKEN($_rule)';
}
class _StringRule extends _Rule implements _Expectable {
final String _string;
int _len;
_StringRule(this._string) : _len = _string.length;
_match(_ParserState state, int pos) {
if (pos + _len > state._end) return null;
for (int i = 0; i < _len; i++) {
if (state._text.codeUnitAt(pos + i) != _string.codeUnitAt(i)) return null;
}
return [pos + _len, null];
}
//get defaultValue => _string;
toString() => '"$_string"';
description() => "'$_string'";
}
class _RegExpRule extends _Rule {
RegExp _re;
_RegExpRule(this._re) {
// There is no convenient way to match an anchored substring.
throw new Exception('RegExp matching not supported');
}
toString() => '"$_re"';
}
class _LexicalRule extends _Rule implements _Expectable {
final String? _name;
final _Rule _rule;
_LexicalRule(this._name, this._rule);
_match(_ParserState state, int pos) {
state.inWhitespaceMode = true;
state.inhibitExpectedTrackingDepth++;
var match = _rule.matchAfterWS(state, pos);
state.inhibitExpectedTrackingDepth--;
state.inWhitespaceMode = false;
return match;
}
toString() => _name.toString();
description() => _name == null ? '?' : _name!;
}
class _TextValueRule extends _Rule {
final _Rule _rule;
final _extract; // Function
_TextValueRule(_Rule this._rule, Function this._extract);
_match(_ParserState state, int pos) {
var match = _rule.matchAfterWS(state, pos);
if (match == null) {
return null;
}
var endPos = match[0];
return [endPos, _extract(state._text, pos, endPos)];
}
bool get generatesValue => true;
toString() => 'TEXT($_rule)';
}
_Rule _compileMultiRule(
List rules, bool allowReducer, finish(compiledRules, valueCount, reducer)) {
int valueCount = 0;
List compiledRules = <_Rule>[];
Function? reducer;
for (var rule in rules) {
if (reducer != null)
throw new Exception('Reducer must be last in sequence: $rule');
if (rule is Function) {
if (allowReducer)
reducer = rule;
else
throw new Exception('Bad rule: "$rule"');
} else {
_Rule compiledRule = _compile(rule);
if (compiledRule.generatesValue) ++valueCount;
compiledRules.add(compiledRule);
}
}
return finish(compiledRules, valueCount, reducer);
}
String _formatMultiRule(String functor, List rules) {
var sb = new StringBuffer(functor);
sb.write('(');
var separator = '';
for (var rule in rules) {
sb.write(separator);
sb.write(rule);
separator = ',';
}
sb.write(')');
return sb.toString();
}
class _SequenceRule extends _Rule {
// This rule matches the component rules in order.
final List<_Rule> _rules;
final int _generatingSubRules;
final Function? _reducer;
bool _generatesValue;
_SequenceRule(List<_Rule> this._rules, int this._generatingSubRules,
Function? this._reducer)
: _generatesValue = _generatingSubRules > 0 || _reducer != null;
_match(state, pos) {
var sequence = [];
for (var rule in _rules) {
var match = rule.match(state, pos);
if (match == null) return null;
if (rule.generatesValue) {
var ast = match[1];
sequence.add(ast);
}
pos = match[0];
}
if (_reducer == null) {
if (_generatingSubRules == 0) return [pos, null];
if (_generatingSubRules == 1) return [pos, sequence[0]];
return [pos, sequence];
} else {
return [pos, _apply(_reducer, sequence)];
}
}
bool get generatesValue => _generatesValue;
toString() => _formatMultiRule('SEQ', _rules);
}
class _ChoiceRule extends _Rule {
// This rule matches the first component rule that matches.
List<_Rule> _rules;
_ChoiceRule(List<_Rule> this._rules);
_match(state, pos) {
for (var rule in _rules) {
var match = rule.match(state, pos);
if (match != null) {
/*
if (!rule.generatesValue) {
var value = rule.defaultValue;
if (value != null)
return [match[0], value];
}
*/
return match;
}
}
return null;
}
bool get generatesValue => true;
toString() => _formatMultiRule('OR', _rules);
}
class _OptionalRule extends _Rule {
_Rule _rule;
_OptionalRule(_Rule this._rule);
_match(_ParserState state, int pos) {
var match = _rule.match(state, pos);
if (_rule.generatesValue) return match == null ? [pos, null] : match;
return match == null ? [pos, false] : [match[0], true];
}
bool get generatesValue => true;
toString() => 'MAYBE($_rule)';
}
class _ContextRule extends _Rule {
_Rule _rule;
_ContextRule(_Rule this._rule);
_match(_ParserState state, int pos) {
// TODO: protect error state.
var match = _rule._match(state, pos);
if (match == null) return null;
return [pos, null];
}
toString() => 'AT($_rule)';
}
class _NegativeContextRule extends _Rule {
_Rule _rule;
_NegativeContextRule(_Rule this._rule);
_match(_ParserState state, int pos) {
// TODO: protect error state.
var match = _rule._match(state, pos);
if (match == null) return [pos, null];
return null;
}
toString() => 'NOT($_rule)';
}
class _RepeatRule extends _Rule {
// Matches zero, one or more items.
_Rule _rule;
_Rule? _separator;
int _min;
_RepeatRule(this._rule, this._separator, this._min);
_match(state, pos) {
// First match.
var match = _rule.match(state, pos);
if (match == null) if (_min == 0)
return [pos, []];
else
return null;
pos = match[0];
var result = [match[1]];
// Subsequent matches:
while (true) {
var newPos = pos;
if (_separator != null) {
match = _separator!.match(state, pos);
if (match == null) return [pos, result];
newPos = match[0];
}
match = _rule.match(state, newPos);
if (match == null) return [pos, result];
pos = match[0];
result.add(match[1]);
}
}
bool get generatesValue => true;
toString() =>
'MANY(min:$_min, $_rule${_separator == null ? '' : ", sep: $_separator"})';
}
class _MemoRule extends _Rule {
final _Rule _rule;
var parseInstance;
// A map from position to result. Can this be replaced with something
// smaller?
// TODO: figure out how to discard the map and parseInstance after parsing.
Map<int, Object> map = {};
_MemoRule(this._rule);
_match(state, pos) {
// See if we are still parsing the same input. Relies on the fact that the
// input is a string and strings are immutable.
if (!identical(parseInstance, state._text)) {
map = new Map<int, Object>();
parseInstance = state._text;
}
// TODO: does this have to check or preserve parse state (like
// inWhitespaceMode, error position info etc?)
// Stored result can be null (memoized failure).
if (map.containsKey(pos)) {
return map[pos];
}
var match = _rule.match(state, pos);
map[pos] = match;
return match;
}
bool get generatesValue => _rule.generatesValue;
toString() => 'MEMO($_rule)';
}
_apply(fn, List args) {
switch (args.length) {
case 0:
return fn();
case 1:
return fn(args[0]);
case 2:
return fn(args[0], args[1]);
case 3:
return fn(args[0], args[1], args[2]);
case 4:
return fn(args[0], args[1], args[2], args[3]);
case 5:
return fn(args[0], args[1], args[2], args[3], args[4]);
case 6:
return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7:
return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8:
return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
args[7]);
case 9:
return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
args[7], args[8]);
case 10:
return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
args[7], args[8], args[9]);
default:
throw new Exception('Too many arguments in _apply: $args');
}
}
List _unspread(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v,
w, x, y, z) {
List list = [];
add(element) {
if (element != null) list.add(element);
}
add(a);
add(b);
add(c);
add(d);
add(e);
add(f);
add(g);
add(h);
add(i);
add(j);
add(k);
add(l);
add(m);
add(n);
add(o);
add(p);
add(q);
add(r);
add(s);
add(t);
add(u);
add(v);
add(w);
add(x);
add(y);
add(z);
return list;
}

View file

@ -1,18 +0,0 @@
# 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.
[ $arch == arm ]
*: Skip
[ $arch == simarm ]
*: Skip
[ $arch == simarm64 ]
*: Skip
[ $arch == simarm64c ]
*: Skip
[ $arch == x64 ]
*: Skip

View file

@ -1,405 +0,0 @@
// 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.
library peg_tests;
import 'dart:core' hide Symbol;
import '../../peg/pegparser.dart';
testParens() {
Grammar g = new Grammar();
Symbol a = g['A'];
a.def = ['(', MANY(a, min: 0), ')', (a) => a];
check(g, a, "", null);
check(g, a, "()", '[]');
check(g, a, "(()())", '[[],[]]');
check(g, a, "(()((()))())", '[[],[[[]]],[]]');
}
testBlockComment() {
// Block comment in whitespace.
Grammar g = new Grammar();
Symbol blockComment = g['blockComment'];
blockComment.def = [
'/*',
MANY(
OR([
blockComment,
[NOT('*/'), CHAR()],
[END, ERROR('EOF in block comment')]
]),
min: 0),
'*/'
];
print(blockComment);
var a = MANY(TEXT('x'));
g.whitespace = OR([g.whitespace, blockComment]);
check(g, a, "x /**/ x", '[x,x]');
check(g, a, "x /*/**/*/ x", '[x,x]');
check(g, a, "x /*/***/ x", 'EOF in block comment');
check(g, a, "x /*/*/x**/**/ x", '[x,x]');
check(
g,
a,
r"""
/* Comment */
/* Following comment with /* nested comment*/ */
x
/* x in comment */
x /* outside comment */
""",
'[x,x]');
}
testTEXT() {
Grammar g = new Grammar();
// TEXT grabs the parsed text,
check(g, TEXT(LEX(MANY(OR(['1', 'a'])))), ' 1a1 ', '1a1');
// Without the lexical context, TEXT will grab intervening whitespace.
check(g, TEXT(MANY(OR(['1', 'a']))), ' 1a1 ', '1a1');
check(g, TEXT(MANY(OR(['1', 'a']))), ' 1 a 1 ', '1 a 1');
// Custom processing of the TEXT substring.
var binaryNumber = TEXT(LEX(MANY(OR(['0', '1']))), (String str, start, end) {
var r = 0;
var zero = '0'.codeUnitAt(0);
for (int i = start; i < end; i++) r = r * 2 + (str.codeUnitAt(i) - zero);
return r;
});
check(g, binaryNumber, ' 10101 ', 21);
check(g, binaryNumber, '1010111', 87);
check(g, binaryNumber, '1010 111', null);
}
testOR() {
// OR matches the first match.
Grammar g = new Grammar();
check(
g,
OR([
['a', NOT(END), () => 1],
['a', () => 2],
['a', () => 3]
]),
'a',
2);
}
testCODE() {
Grammar g = new Grammar();
var a = TEXT(LEX('thing', MANY(CHAR('bcd'))));
check(g, a, 'bbb', 'bbb');
check(g, a, 'ccc', 'ccc');
check(g, a, 'ddd', 'ddd');
check(g, a, 'bad', null); // a is outside range.
check(g, a, 'bed', null); // e is outside range.
}
testC() {
// Curried tree builders.
binary(operation) => (second) => (first) => [operation, first, second];
unary(operation) => () => (first) => [operation, first];
reform(a, fns) {
var r = a;
for (var fn in fns) r = fn(r);
return r;
}
Grammar g = new Grammar();
Symbol expression = g['expression'];
Symbol postfix_e = g['postfix_e'];
Symbol unary_e = g['unary_e'];
Symbol cast_e = g['cast_e'];
Symbol mult_e = g['mult_e'];
Symbol add_e = g['add_e'];
Symbol shift_e = g['shift_e'];
Symbol relational_e = g['relational_e'];
Symbol equality_e = g['equality_e'];
Symbol cond_e = g['cond_e'];
Symbol assignment_e = g['assignment_e'];
// Lexical elements.
var idStartChar =
CHAR(r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
var idNextChar =
CHAR(r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$_");
var id = TEXT(LEX('identifier', [idStartChar, MANY(idNextChar, min: 0)]));
var lit = TEXT(LEX('literal', MANY(CHAR('0123456789'))));
var type_name = id;
// Expression grammar.
var primary_e = OR([
id,
lit,
['(', expression, ')', (e) => e]
]);
var postfixes = OR([
['(', MANY(assignment_e, separator: ',', min: 0), ')', binary('apply')],
['++', unary('postinc')],
['--', unary('postdec')],
['.', id, binary('field')],
['->', id, binary('ptr')],
]);
postfix_e.def = [primary_e, MANY(postfixes, min: 0), reform];
var unary_op = OR([
['&', () => 'address'],
['*', () => 'indir'],
['!', () => 'not'],
['~', () => 'not'],
['-', () => 'negate'],
['+', () => 'uplus'],
]);
var sizeof = LEX('sizeof', ['sizeof', NOT(idNextChar)]);
Symbol unary_e_plain = g['unary_e_plain'];
unary_e_plain.def = OR([
[
'++', unary_e, (e) => ['preinc', e] //
],
[
'--', unary_e, (e) => ['predec', e] //
],
[
unary_op, cast_e, (o, e) => [o, e] //
],
[
sizeof, unary_e, (e) => ['sizeof-expr', e] //
],
[
sizeof, '(', type_name, ')', (t) => ['sizeof-type', t] //
],
postfix_e
]);
unary_e.def = MEMO(unary_e_plain);
//unary_e.def = unary_e_plain;
cast_e.def = OR([
[
'(', type_name, ')', cast_e, (t, e) => ['cast', t, e] //
],
unary_e,
]);
var mult_ops = OR([
['*', cast_e, binary('mult')],
['/', cast_e, binary('div')],
['%', cast_e, binary('rem')],
]);
mult_e.def = [cast_e, MANY(mult_ops, min: 0), reform];
var add_ops = OR([
['+', mult_e, binary('add')],
['-', mult_e, binary('sub')],
]);
add_e.def = [mult_e, MANY(add_ops, min: 0), reform];
var shift_ops = OR([
['>>', add_e, binary('shl')],
['<<', add_e, binary('shr')],
]);
shift_e.def = [add_e, MANY(shift_ops, min: 0), reform];
var relational_ops = OR([
['<=', shift_e, binary('le')],
['>=', shift_e, binary('ge')],
['<', shift_e, binary('lt')],
['>', shift_e, binary('gt')],
]);
relational_e.def = [shift_e, MANY(relational_ops, min: 0), reform];
var equality_ops = OR([
['==', shift_e, binary('eq')],
['!=', shift_e, binary('ne')],
]);
equality_e.def = [relational_e, MANY(equality_ops, min: 0), reform];
var bit_and_op = LEX('&', ['&', NOT('&')]); // Don't see '&&' and '&', '&'
var bit_or_op = LEX('|', ['|', NOT('|')]);
var and_e = [
equality_e,
MANY([bit_and_op, equality_e, binary('bitand')], min: 0),
reform
];
var xor_e = [
and_e,
MANY(['^', and_e, binary('bitxor')], min: 0),
reform
];
var or_e = [
xor_e,
MANY([bit_or_op, xor_e, binary('bitor')], min: 0),
reform
];
var log_and_e = [
or_e,
MANY(['&&', or_e, binary('and')], min: 0),
reform
];
var log_or_e = [
log_and_e,
MANY(['||', log_and_e, binary('or')], min: 0),
reform
];
//cond_e.def = OR([ [log_or_e, '?', expression, ':', cond_e,
// (p,a,b) => ['cond', p, a, b]],
// log_or_e]);
// Alternate version avoids reparsing log_or_e.
cond_e.def = [
log_or_e,
MAYBE(['?', expression, ':', cond_e]),
(p, r) => r == null || r == false ? p : ['cond', p, r[0], r[1]]
];
var assign_op = OR([
['*=', () => 'mulassign'],
['=', () => 'assign']
]);
// TODO: Figure out how not to re-parse a unary_e.
// Order matters - cond_e can't go first since cond_e will succeed on, e.g. 'a'.
assignment_e.def = OR([
[
unary_e,
assign_op,
assignment_e,
(u, op, a) => [op, u, a]
],
cond_e
]);
expression.def = [
assignment_e,
MANY([',', assignment_e, binary('comma')], min: 0),
reform
];
show(g, expression, 'a');
check(g, expression, 'a', 'a');
check(g, expression, '(a)', 'a');
check(g, expression, ' ( ( a ) ) ', 'a');
check(g, expression, 'a(~1,2)', '[apply,a,[[not,1],2]]');
check(g, expression, 'a(1)(x,2)', '[apply,[apply,a,[1]],[x,2]]');
check(g, expression, 'a(1,2())', '[apply,a,[1,[apply,2,[]]]]');
check(g, expression, '++a++', '[preinc,[postinc,a]]');
check(g, expression, 'a++++b', null);
check(g, expression, 'a++ ++b', null);
check(g, expression, 'a+ +++b', '[add,a,[preinc,[uplus,b]]]');
check(g, expression, 'a+ + ++b', '[add,a,[uplus,[preinc,b]]]');
check(g, expression, 'a+ + + +b', '[add,a,[uplus,[uplus,[uplus,b]]]]');
check(g, expression, 'a+ ++ +b', '[add,a,[preinc,[uplus,b]]]');
check(g, expression, 'a++ + +b', '[add,[postinc,a],[uplus,b]]');
check(g, expression, 'a+++ +b', '[add,[postinc,a],[uplus,b]]');
check(g, expression, '((T)f)(x)', '[apply,[cast,T,f],[x]]');
check(g, expression, '(T)f(x)', '[cast,T,[apply,f,[x]]]');
check(g, expression, 'a++*++b', '[mult,[postinc,a],[preinc,b]]');
check(g, expression, 'a<<1>>++b', '[shl,[shr,a,1],[preinc,b]]');
check(g, expression, 'a<1&&b', '[and,[lt,a,1],b]');
check(g, expression, 'a<1 & &b', '[bitand,[lt,a,1],[address,b]]');
check(g, expression, 'a ? b ? c : d : e ? f : g',
'[cond,a,[cond,b,c,d],[cond,e,f,g]]');
check(g, expression, 'a,b,c', '[comma,[comma,a,b],c]');
check(g, expression, 'a=1,b,c', '[comma,[comma,[assign,a,1],b],c]');
check(g, expression, '((((((((((((a))))))))))))=1,b,c',
'[comma,[comma,[assign,a,1],b],c]');
check(g, expression, 'sizeof a', '[sizeof-expr,a]');
check(g, expression, 'sizeofa', 'sizeofa');
check(g, expression, 'sizeof (a)', '[sizeof-expr,a]');
}
show(grammar, rule, input) {
print('show: "$input"');
var ast;
try {
ast = grammar.parse(rule, input);
} catch (exception) {
if (exception is ParseError)
ast = exception;
else
rethrow;
}
print('${printList(ast)}');
}
void check(grammar, rule, input, expected) {
// If [expected] is String then the result is coerced to string.
// If [expected] is !String, the result is compared directly.
print('check: "$input"');
var ast;
try {
ast = grammar.parse(rule, input);
} catch (exception) {
ast = exception;
}
var formatted = ast;
if (expected is String) formatted = printList(ast);
//Expect.equals(expected, formatted, "parse: $input");
if (expected != formatted) {
throw new ArgumentError("parse: $input"
"\n expected: $expected"
"\n found: $formatted");
}
}
// Prints the list in [1,2,3] notation, including nested lists.
printList(item) {
if (item is List) {
StringBuffer sb = new StringBuffer();
sb.write('[');
var sep = '';
for (var x in item) {
sb.write(sep);
sb.write(printList(x));
sep = ',';
}
sb.write(']');
return sb.toString();
}
if (item == null) return 'null';
return item.toString();
}
main() {
testCODE();
testParens();
testOR();
testTEXT();
testBlockComment();
testC();
}