| // Copyright (c) 2019, 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. |
| |
| import "package:front_end/src/fasta/scanner.dart" show scanString, Token; |
| |
| abstract class ParsedType { |
| R accept<R, A>(Visitor<R, A> visitor, [A a]); |
| } |
| |
| class ParsedInterfaceType extends ParsedType { |
| final String name; |
| |
| final List<ParsedType> arguments; |
| |
| ParsedInterfaceType(this.name, this.arguments); |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write(name); |
| if (arguments.isNotEmpty) { |
| sb.write("<"); |
| sb.writeAll(arguments, ", "); |
| sb.write(">"); |
| } |
| return "$sb"; |
| } |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitInterfaceType(this, a); |
| } |
| } |
| |
| abstract class ParsedDeclaration extends ParsedType { |
| final String name; |
| |
| ParsedDeclaration(this.name); |
| } |
| |
| class ParsedClass extends ParsedDeclaration { |
| final List<ParsedTypeVariable> typeVariables; |
| final ParsedInterfaceType supertype; |
| final List<ParsedType> interfaces; |
| final ParsedFunctionType callableType; |
| |
| ParsedClass(String name, this.typeVariables, this.supertype, this.interfaces, |
| this.callableType) |
| : super(name); |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("class "); |
| sb.write(name); |
| if (typeVariables.isNotEmpty) { |
| sb.write("<"); |
| sb.writeAll(typeVariables, ", "); |
| sb.write(">"); |
| } |
| if (supertype != null) { |
| sb.write(" extends "); |
| sb.write(supertype); |
| } |
| if (interfaces.isNotEmpty) { |
| sb.write(" implements "); |
| sb.writeAll(interfaces, ", "); |
| } |
| if (callableType != null) { |
| sb.write("{\n "); |
| sb.write(callableType); |
| sb.write("\n}"); |
| } else { |
| sb.write(";"); |
| } |
| return "$sb"; |
| } |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitClass(this, a); |
| } |
| } |
| |
| class ParsedTypedef extends ParsedDeclaration { |
| final List<ParsedTypeVariable> typeVariables; |
| |
| final ParsedType type; |
| |
| ParsedTypedef(String name, this.typeVariables, this.type) : super(name); |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("typedef "); |
| sb.write(name); |
| if (typeVariables.isNotEmpty) { |
| sb.write("<"); |
| sb.writeAll(typeVariables, ", "); |
| sb.write(">"); |
| } |
| sb.write(" "); |
| sb.write(type); |
| return "$sb;"; |
| } |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitTypedef(this, a); |
| } |
| } |
| |
| class ParsedFunctionType extends ParsedType { |
| final ParsedType returnType; |
| |
| final ParsedArguments arguments; |
| |
| ParsedFunctionType(this.returnType, this.arguments); |
| |
| String toString() { |
| return "$arguments -> $returnType"; |
| } |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitFunctionType(this, a); |
| } |
| } |
| |
| class ParsedVoidType extends ParsedType { |
| String toString() => "void"; |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitVoidType(this, a); |
| } |
| } |
| |
| class ParsedTypeVariable extends ParsedType { |
| final String name; |
| |
| final ParsedType bound; |
| |
| ParsedTypeVariable(this.name, this.bound); |
| |
| String toString() => name; |
| |
| R accept<R, A>(Visitor<R, A> visitor, [A a]) { |
| return visitor.visitTypeVariable(this, a); |
| } |
| } |
| |
| class ParsedArguments { |
| final List<ParsedType> required; |
| final List optional; |
| final bool optionalAreNamed; |
| |
| ParsedArguments(this.required, this.optional, this.optionalAreNamed); |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("("); |
| sb.writeAll(required, ", "); |
| if (optional.isNotEmpty) { |
| if (required.isNotEmpty) { |
| sb.write(", "); |
| } |
| if (optionalAreNamed) { |
| sb.write("{"); |
| for (int i = 0; i < optional.length; i += 2) { |
| if (i != 0) { |
| sb.write(", "); |
| } |
| sb.write(optional[i]); |
| sb.write(" "); |
| sb.write(optional[i + 1]); |
| } |
| sb.write("}"); |
| } else { |
| sb.write("["); |
| sb.writeAll(optional, ", "); |
| sb.write("]"); |
| } |
| } |
| sb.write(")"); |
| return "$sb"; |
| } |
| } |
| |
| class Parser { |
| Token peek; |
| |
| String source; |
| |
| Parser(this.peek, this.source); |
| |
| bool get atEof => peek.isEof; |
| |
| void advance() { |
| peek = peek.next; |
| } |
| |
| void expect(String string) { |
| if (!identical(string, peek.stringValue)) { |
| String error = "${source.substring(0, peek.charOffset)}\n>>>" |
| "\n${source.substring(peek.charOffset)}"; |
| throw "Expected `$string`, but got `${peek.lexeme}`\n$error"; |
| } |
| advance(); |
| } |
| |
| bool optional(String value) { |
| return identical(value, peek.stringValue); |
| } |
| |
| bool optionalAdvance(String value) { |
| if (optional(value)) { |
| advance(); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| ParsedType parseType() { |
| if (optional("class")) return parseClass(); |
| if (optional("typedef")) return parseTypedef(); |
| if (optional("(")) return parseFunctionType(); |
| String name = parseName(); |
| List<ParsedType> arguments = <ParsedType>[]; |
| if (optional("<")) { |
| advance(); |
| arguments.add(parseType()); |
| while (optional(",")) { |
| advance(); |
| arguments.add(parseType()); |
| } |
| expect(">"); |
| } |
| return new ParsedInterfaceType(name, arguments); |
| } |
| |
| ParsedType parseReturnType() { |
| if (optionalAdvance("void")) return new ParsedVoidType(); |
| return parseType(); |
| } |
| |
| ParsedFunctionType parseFunctionType() { |
| ParsedArguments arguments = parseArguments(); |
| expect("-"); |
| expect(">"); |
| ParsedType returnType = parseReturnType(); |
| return new ParsedFunctionType(returnType, arguments); |
| } |
| |
| String parseName() { |
| if (!peek.isIdentifier) { |
| throw "Expected a name, but got `${peek.stringValue}`"; |
| } |
| String result = peek.lexeme; |
| advance(); |
| return result; |
| } |
| |
| ParsedArguments parseArguments() { |
| List<ParsedType> requiredArguments = <ParsedType>[]; |
| List optionalArguments = []; |
| bool optionalAreNamed = false; |
| expect("("); |
| do { |
| if (optional(")")) break; |
| if (optionalAdvance("[")) { |
| do { |
| optionalArguments.add(parseType()); |
| } while (optionalAdvance(",")); |
| expect("]"); |
| break; |
| } else if (optionalAdvance("{")) { |
| optionalAreNamed = true; |
| do { |
| optionalArguments.add(parseType()); |
| optionalArguments.add(parseName()); |
| } while (optionalAdvance(",")); |
| expect("}"); |
| break; |
| } else { |
| requiredArguments.add(parseType()); |
| } |
| } while (optionalAdvance(",")); |
| expect(")"); |
| return new ParsedArguments( |
| requiredArguments, optionalArguments, optionalAreNamed); |
| } |
| |
| List<ParsedTypeVariable> parseTypeVariablesOpt() { |
| List<ParsedTypeVariable> typeVariables = <ParsedTypeVariable>[]; |
| if (optionalAdvance("<")) { |
| do { |
| typeVariables.add(parseTypeVariable()); |
| } while (optionalAdvance(",")); |
| expect(">"); |
| } |
| return typeVariables; |
| } |
| |
| ParsedTypeVariable parseTypeVariable() { |
| String name = parseName(); |
| ParsedType bound; |
| if (optionalAdvance("extends")) { |
| bound = parseType(); |
| } |
| return new ParsedTypeVariable(name, bound); |
| } |
| |
| ParsedClass parseClass() { |
| expect("class"); |
| String name = parseName(); |
| List<ParsedTypeVariable> typeVariables = parseTypeVariablesOpt(); |
| ParsedType supertype; |
| if (optionalAdvance("extends")) { |
| supertype = parseType(); |
| } |
| List<ParsedType> interfaces = <ParsedType>[]; |
| if (optionalAdvance("implements")) { |
| do { |
| interfaces.add(parseType()); |
| } while (optionalAdvance(",")); |
| } |
| ParsedFunctionType callableType; |
| if (optionalAdvance("{")) { |
| callableType = parseFunctionType(); |
| expect("}"); |
| } else { |
| expect(";"); |
| } |
| return new ParsedClass( |
| name, typeVariables, supertype, interfaces, callableType); |
| } |
| |
| /// This parses a general typedef on this form: |
| /// |
| /// typedef <name> <type-variables-opt> <type> ; |
| /// |
| /// This is unlike Dart typedef. |
| ParsedTypedef parseTypedef() { |
| expect("typedef"); |
| String name = parseName(); |
| List<ParsedTypeVariable> typeVariables = parseTypeVariablesOpt(); |
| ParsedType type = parseType(); |
| expect(";"); |
| return new ParsedTypedef(name, typeVariables, type); |
| } |
| } |
| |
| List<ParsedType> parse(String text) { |
| Parser parser = new Parser(scanString(text).tokens, text); |
| List<ParsedType> types = <ParsedType>[]; |
| while (!parser.atEof) { |
| types.add(parser.parseType()); |
| } |
| return types; |
| } |
| |
| abstract class DefaultAction<R, A> { |
| R defaultAction(ParsedType node, A a); |
| |
| static perform<R, A>(Visitor<R, A> visitor, ParsedType node, A a) { |
| if (visitor is DefaultAction<R, A>) { |
| DefaultAction<R, A> defaultAction = visitor as DefaultAction<R, A>; |
| return defaultAction.defaultAction(node, a); |
| } else { |
| return null; |
| } |
| } |
| } |
| |
| abstract class Visitor<R, A> { |
| R visitInterfaceType(ParsedInterfaceType node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| |
| R visitClass(ParsedClass node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| |
| R visitTypedef(ParsedTypedef node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| |
| R visitFunctionType(ParsedFunctionType node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| |
| R visitVoidType(ParsedVoidType node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| |
| R visitTypeVariable(ParsedTypeVariable node, A a) { |
| return DefaultAction.perform<R, A>(this, node, a); |
| } |
| } |