UNPKG

minigrace

Version:

A compiler for the Grace programming language

848 lines 1.07 MB
let gracecode_parser_sourceFile = "/Users/black/Development/mg/gracelang/minigrace/parser.grace"; let gracecode_parser_sha256 = "a7b683f7eebbe09be105d7c8702dd1ebeee9da02f695a1e579475d61ee66613a"; let gracecode_parser_minigraceRevision = "b57591d29fc5ee5270d114920bf671367b8c3ecb"; let gracecode_parser_minigraceGeneration = "5171"; if (typeof gctCache !== "undefined") gctCache["parser"] = "dialect:\n standard\nfreshScopes:\n $102\n $103\n $104\n $106\nmethodTypes:$101:\n blockParameter(params:Unknown) \u2192 Boolean\nmethodTypes:$102:\n end \u2192 Position\n start \u2192 Position\nmodules:\n ast\n basic\n errormessages\n io\n standard\n util\npath:\n /Users/black/Development/mg/gracelang/minigrace/parser.grace\nscope:$101:\n AstNode type\n CompilerError Unknown (mth) $scope_done\n GatheringError Unknown (mth) $scope_done\n Position type\n Range type\n Scope type\n Variable type\n accept(1) Unknown (mth) $scope_done\n acceptArgument Unknown (mth) $scope_done\n acceptDotOuter Unknown (mth) $scope_done\n acceptKeyword(1) Unknown (mth) $scope_done\n acceptKeyword(1)or(1) Unknown (mth) $scope_done\n acceptKeyword(1)or(1)or(1) Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n basicAsString String (go) $scope_string\n block Unknown (mth) $scope_done\n blockBody(1)beginningWith(1) Unknown (mth) $scope_done\n blockParameter(1) Boolean (mth) $scope_done\n blockParameters Unknown (mth) $scope_done\n callrest(1) Unknown (mth) $scope_done\n canonicalName(1) Unknown (mth) $scope_done\n checkAnnotation(1) Unknown (mth) $scope_done\n checkBadInterfaceLiteral Unknown (mth) $scope_done\n checkBadOperators Unknown (mth) $scope_done\n checkForSeparatorInInterface Unknown (mth) $scope_done\n checkUnexpectedTokenAfterStatement Unknown (mth) $scope_done\n checkWhereCondition Unknown (mth) $scope_done\n classOrTrait(1) Unknown (mth) $scope_done\n defdec Unknown (mth) $scope_done\n doannotation Unknown (mth) $scope_done\n dodialect Unknown (mth) $scope_done\n doif Unknown (mth) $scope_done\n doimport Unknown (mth) $scope_done\n doobject Unknown (mth) $scope_done\n doouter Unknown (mth) $scope_done\n doreturn Unknown (mth) $scope_done\n doself Unknown (mth) $scope_done\n dotrest(1) Unknown (mth) $scope_done\n emptyRange Unknown (mth) $scope_done\n errorDefMissingRhs(1) Unknown (mth) $scope_done\n errorDefNoExpression Unknown (mth) $scope_done\n errorDefNoName Unknown (mth) $scope_done\n errorDefUsesAssign(1) Unknown (mth) $scope_done\n errorMissingAnnotation Unknown (mth) $scope_done\n errorMissingComma Unknown (mth) $scope_done\n errorMissingIdentifier Unknown (mth) $scope_done\n errorNoVarArgs Unknown (mth) $scope_done\n errorUnexpectedKeyword Unknown (mth) $scope_done\n expression(1) Unknown (mth) $scope_done\n expressionrest(1)recursingWith(1)blocks(1) Unknown (mth) $scope_done\n fakeSymbolTable Unknown (mth) $103\n findClosingBrace(2) Unknown (mth) $scope_done\n findNextToken(1) Unknown (mth) $scope_done\n findNextTokenIndentedAt(1) Unknown (mth) $scope_done\n findNextValidToken(1) Unknown (mth) $scope_done\n generic Unknown (mth) $scope_done\n identifier Unknown (mth) $scope_done\n inheritModifier(1) Unknown (mth) $scope_done\n inheritOrUse Unknown (mth) $scope_done\n interfaceLiteral Unknown (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n isOnAContinationLine Unknown (mth) $scope_done\n line(1)column(1) Position (mth) $104\n matchcase Unknown (mth) $scope_done\n methodClassOrTrait Unknown (mth) $scope_done\n methodDecRest(1) Unknown (mth) $scope_done\n methodDeclaration(1) Unknown (mth) $scope_done\n methodHeader Unknown (mth) $scope_done\n methodInInterface Unknown (mth) $scope_done\n methodInInterface(1) Unknown (mth) $scope_done\n methodSignature Unknown (mth) $scope_done\n myIdentityHash Number (go) $scope_number\n newIf(3) Unknown (mth) $scope_done\n next Unknown (mth) $scope_done\n nextToken Unknown (mth) $scope_done confidential\n noPosition Unknown (mth) $scope_done\n nullNode AstNode (mth) $105\n numericName(1) Unknown (mth) $scope_done\n operator(1) Unknown (mth) $102\n optionalTypeAnnotation Unknown (mth) $scope_done\n parameterList(1) Unknown (mth) $scope_done\n parenthesizedArgs(1)startingWith(1) Unknown (mth) $scope_done\n parse(1) Unknown (mth) $scope_done\n parseAlias(1) Unknown (mth) $scope_done\n parseArgumentsFor(1)into(1)acceptBlocks(1) Unknown (mth) $scope_done\n parseExclude(1) Unknown (mth) $scope_done\n parseObjectConstructorBody(1)startingWith(1)after(1) Unknown (mth) $scope_done\n prefixop Unknown (mth) $scope_done\n pushComments Unknown (mth) $scope_done\n pushIdentifier Unknown (mth) $scope_done\n pushNum Unknown (mth) $scope_done\n pushString Unknown (mth) $scope_done\n reconcileComments Unknown (mth) $scope_done\n reportBadRhs Unknown (mth) $scope_done\n reportMissingArrow Unknown (mth) $scope_done\n reportSyntaxError(1)before(1) Unknown (mth) $scope_done\n restoreParsePosition(1) Unknown (mth) $scope_done\n saveParsePosition Unknown (mth) $scope_done\n separator Unknown (mth) $scope_done\n sequenceConstructor Unknown (mth) $scope_done\n skipSeparators Unknown (mth) $scope_done\n start(1)end(1) Range (mth) $106\n startsStatement Unknown (mth) $scope_done\n statement Unknown (mth) $scope_done\n successfulParse(1) Unknown (mth) $scope_done\n term Unknown (mth) $scope_done\n toprec(1) Unknown (mth) $scope_done\n trycatch Unknown (mth) $scope_done\n typeArgs Unknown (mth) $scope_done\n typedec Unknown (mth) $scope_done\n typedec(1) Unknown (mth) $scope_done\n typeexpression Unknown (mth) $scope_done\n typeexpressionrest Unknown (mth) $scope_done\n typeparameters Unknown (mth) $scope_done\n typeterm Unknown (mth) $scope_done\n unsuccessfulParse(1) Unknown (mth) $scope_done\n valueexpressionrest Unknown (mth) $scope_done\n vardec Unknown (mth) $scope_done\nscope:$102:\n asDebugString String (go) $scope_string\n asString String (go) $scope_string\n basicAsString String (go) $scope_string\n end Position (def) $scopeEmpty public\n isArithmetic Unknown (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n myIdentityHash Number (go) $scope_number\n op Unknown (def) $scopeEmpty public\n precedence Unknown (mth) $scope_done\n start Position (def) $scopeEmpty public\n symbol Unknown (def) $scopeEmpty\n typeArgs Unknown (var) $scopeEmpty public\n typeArgs:=(1) Unknown (var) $scopeEmpty public\nscope:$103:\n ::(1) Unknown (mth) $scope_done\n ==(1) Unknown (mth) $scope_done\n areReusedNamesCompleted Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n hash Unknown (mth) $scope_done\n isFresh Unknown (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n localNames Unknown (mth) $scope_done\n myIdentityHash Number (go) $scope_number\n node Unknown (var) $scopeEmpty\n node:=(1) Unknown (var) $scopeEmpty\n prefix== Unknown (mth) $scope_done\n prefix\u2260 Unknown (mth) $scope_done\n variety Unknown (mth) $scope_done\n varsAreMethods Unknown (mth) $scope_done\n \u2260(1) Unknown (mth) $scope_done\nscope:$104:\n ::(1) Unknown (mth) $scope_done\n <(1) Boolean (mth) $scope_done\n ==(1) Boolean (mth) $scope_done\n >(1) Boolean (mth) $scope_done\n addColumn(1) Unknown (mth) $scope_done\n addLine(1) Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n column Unknown (def) $scopeEmpty\n hash Number (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n line Unknown (def) $scopeEmpty\n myIdentityHash Number (go) $scope_number\n prefix== Unknown (mth) $scope_done\n prefix\u2260 Unknown (mth) $scope_done\n \u2260(1) Unknown (mth) $scope_done\n \u2264(1) Boolean (mth) $scope_done\n \u2265(1) Boolean (mth) $scope_done\nscope:$105:\n ::(1) Unknown (mth) $scope_done\n ==(1) Unknown (mth) $scope_done\n accept(1)from(1) Unknown (mth) $scope_done\n annotations Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n childrenDo(1) Unknown (mth) $scope_done\n childrenMap(1) Unknown (mth) $scope_done\n column Unknown (def) $scope_number\n column:=(1) Unknown (mth) $scope_done\n comments Unknown (mth) $scope_done\n decType Unknown (mth) $scope_done\n end Position (mth) $scope_done\n endCol Unknown (mth) $scope_done\n hasAnnotation(1) Unknown (mth) $scope_done\n hash Unknown (mth) $scope_done\n inClass Unknown (mth) $scope_done\n inTrait Unknown (mth) $scope_done\n isAssignment Unknown (mth) $scope_done\n isBlock Unknown (mth) $scope_done\n isBuiltIn Unknown (mth) $scope_done\n isCall Unknown (mth) $scope_done\n isClass Unknown (mth) $scope_done\n isComment Unknown (mth) $scope_done\n isConstant Unknown (mth) $scope_done\n isDeclaredByParent Unknown (mth) $scope_done\n isDialect Unknown (mth) $scope_done\n isExecutable Unknown (mth) $scope_done\n isExternal Unknown (mth) $scope_done\n isFresh Unknown (mth) $scope_done\n isIdentifier Unknown (mth) $scope_done\n isImport Unknown (mth) $scope_done\n isMarkerDeclaration Unknown (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n isMember Unknown (mth) $scope_done\n isMethod Unknown (mth) $scope_done\n isModule Unknown (mth) $scope_done\n isNull Unknown (mth) $scope_done\n isObject Unknown (mth) $scope_done\n isOuter Unknown (mth) $scope_done\n isReturn Unknown (mth) $scope_done\n isSelf Unknown (mth) $scope_done\n isSelfOrOuter Unknown (mth) $scope_done\n isSequenceConstructor Unknown (mth) $scope_done\n isSuper Unknown (mth) $scope_done\n isTrait Unknown (mth) $scope_done\n isTypeDec Unknown (mth) $scope_done\n kind Unknown (def) $scope_string\n line Unknown (def) $scope_number\n line:=(1) Unknown (mth) $scope_done\n map(1)ancestors(1) Unknown (mth) $scope_done\n myIdentityHash Number (go) $scope_number\n nameString Unknown (mth) $scope_done\n newAccept(1) Unknown (mth) $scope_done\n prefix== Unknown (mth) $scope_done\n prefix\u2260 Unknown (mth) $scope_done\n pretty(1) Unknown (mth) $scope_done\n range Unknown (mth) $scope_done\n register Unknown (def) $scope_string\n scope Unknown (def) $103\n shallowCopy Unknown (mth) $scope_done\n start Unknown (mth) $scope_done\n toGrace(1) Unknown (mth) $scope_done\n \u2260(1) Unknown (mth) $scope_done\nscope:$106:\n ::(1) Unknown (mth) $scope_done\n <(1) Unknown (mth) $scope_done\n ==(1) Unknown (mth) $scope_done\n >(1) Unknown (mth) $scope_done\n arrow Unknown (mth) $scope_done\n asDebugString String (go) $scope_string\n asString Unknown (mth) $scope_done\n basicAsString String (go) $scope_string\n column Unknown (mth) $scope_done\n end Unknown (def) $scopeEmpty\n hash Number (mth) $scope_done\n isMe(1) Boolean (go) $scope_boolean\n line Unknown (mth) $scope_done\n lineRangeString Unknown (mth) $scope_done\n myIdentityHash Number (go) $scope_number\n prefix== Unknown (mth) $scope_done\n prefix\u2260 Unknown (mth) $scope_done\n rangeLongString Unknown (mth) $scope_done\n rangeString Unknown (mth) $scope_done\n start Unknown (def) $scopeEmpty\n sugg Unknown (mth) $scope_done\n \u2260(1) Unknown (mth) $scope_done\n \u2264(1) Unknown (mth) $scope_done\n \u2265(1) Unknown (mth) $scope_done\nself:\n $101\ntypes:\n"; if (typeof originalSourceLines !== "undefined") { originalSourceLines["parser"] = [ "dialect \"standard\"", "import \"io\" as io", "import \"ast\" as ast", "import \"util\" as util", "import \"errormessages\" as errormessages", "import \"basic\" as basic", "", "use basic.open", "", "var tokens := false", "var moduleObject", "def comments = list [] // so we can request `removeAt`", "", "var auto_count := 0", "def noBlocks = false", "def blocksOK = true", "", "", "var values := list [ ]", "", "// The alternative definition below allows pushes and pops of `values`", "// to be traced. It can be useful for debugging the parser.", "// def values = object {", "// def realValues = list [ ]", "// var tracing is public := false", "// method push(v) {", "// if (tracing) then {", "// print \"pushed {v.toGrace 0} (line {v.line})\"", "// }", "// realValues.push(v)", "// }", "// method pop {", "// def res = realValues.pop", "// if (tracing) then {", "// print \"popped {res.toGrace 0} (line {res.line})\"", "// }", "// res", "// }", "// method size { realValues.size }", "// method filter(b) { realValues.filter(b) }", "// method isEmpty { realValues.isEmpty }", "// method last { realValues.last }", "// method do(b) { realValues.do(b) }", "// }", "", "// sym is a module-level field referring to the current token", "var sym := object {", " def kind is public = \"start\"", " def line is public = 0", " def column is public = 0", " def indent is public = 0", " def value is public = \"\"", " def size is public = 0", " method ==(other) {", " if (other == false) then {", " false", " } else {", " (other.line == line) && (other.column == column)", " }", " }", "}", "", "var lastToken := sym", "var statementToken := lastToken // the token starting the current statement", "var comment := false", "", "method next {", " // Advance to the next token in the stream, assigning it to sym.", " // Put the position in the input into util module variables.", "", " if (tokens.size > 0) then {", " nextToken", " pushComments", " } else {", " errormessages.syntaxError(\"unexpectedly found the end of the input. \"", " ++ \"This is often caused by a missing '\\}'\")", " atPosition(sym.line, sym.column)", " }", "}", "", "method nextToken is confidential {", " lastToken := sym", " sym := tokens.poll", " if (util.verbosity > 110) then { io.error.write \"{sym}\\n\" }", " util.setPosition(sym.line, sym.column)", "}", "", "method isOnAContinationLine {", " // is current token on a line that is a continuation of the previous line?", " def currentLine = sym.line", " var s := sym", " while {s.line == currentLine} do {", " if (s.hasPrev.not) then { return false }", " s := s.prev", " if (s.isSeparator) then { return false }", " }", " return true", "}", "", "method saveParsePosition {", " def lexerState = tokens.savePosition", " return [lexerState, values.size]", "}", "", "method restoreParsePosition(saved) {", " tokens.restorePosition(saved.first)", " sym := tokens.first.prev", " lastToken := sym.prev", " def oldValueStackSize = saved.second", " if (oldValueStackSize > values.size) then {", " ProgrammingError.raise \"can't restore parse position; the values stack has been popped\"", " }", " while {oldValueStackSize ≠ values.size} do { values.pop }", "}", "", "method findNextToken(tokenMatcher) {", " // Search for the next token for which the given block returns true.", " // Used for generating suggestions.", "", " if (tokenMatcher.apply(sym)) then {", " return sym", " }", " var n := sym", " while {n.isEof.not && { n.indent >= lastToken.indent }} do {", " if (tokenMatcher.apply(n)) then {", " return n", " }", " n := n.next", " }", " n", "}", "", "method findNextTokenIndentedAt(tok) {", " // Search for the next token for whose indent does not exceed that of tok.", " // Used for generating suggestions.", " if (((sym.line > tok.line) && (sym.indent <= tok.indent)) || (sym.isEof)) then {", " return sym", " }", " var n := sym", " while {n.isEof.not} do {", " if ((n.line > tok.line) && (n.indent <= tok.indent)) then {", " return n", " }", " n := n.next", " }", " n", "}", "", "method findNextValidToken(validFollowTokens) {", " // returns the next token in validFollowTokens, or the next token", " // that could start an expression, or eof", "", " def invalidTokens = set.withAll [\"dot\", \"comma\", \"colon\", \"rparen\", \"rbrace\",", " \"rsquare\", \"arrow\", \"assignment\"]; // Tokens that cannot start an expression", "", " var candidate := sym", " while {candidate.isEof.not} do {", " if (validFollowTokens.contains(candidate.kind)) then {", " return candidate // candidate is a valid follow token, so return it", " }", " if (!invalidTokens.contains(candidate.kind)) then {", " return candidate // candidate could start an expression, so return it", " }", " candidate := candidate.next // candidate is invalid, so go to the next one", " }", " return candidate // candidate is eof", "}", "", "method findClosingBrace(opening, inserted) {", " // Finds the closing brace correspondng to opening (that is the beginning of a control", " // structure) -- an opening brace. Returns an object with two fields: found", " // and tok. If a closing brace is found, found is true, and tok is", " // the closing brace. Otherwise, found is false, and tok is the", " // token after which the closing brace should appear.", "", " var n := sym", " var numOpening := if (inserted) then {1} else {0}", " var numClosing := 0", " def result = object {", " var found is public", " var tok is public", " }", " // Count all tokens on the same line first.", " while {(n.isEof.not) && (n.line == opening.line)} do {", " if (n.isLBrace) then {", " numOpening := numOpening + 1", " } elseif { n.isRBrace } then {", " numClosing := numClosing + 1", " }", " n := n.next", " }", " // Count all tokens that have greater indent than the opening brace.", " while {(n.isEof.not) && (n.indent > opening.indent)} do {", " if (n.isLBrace) then {", " numOpening := numOpening + 1", " } elseif { n.isRBrace } then {", " numClosing := numClosing + 1", " }", " n := n.next", " }", " if (n.isRBrace) then {", " result.found := true", " result.tok := n", " } else {", " result.found := false", " result.tok := n.prev", " }", " result", "}", "", "", "method accept(t) {", " // True if the current token has kind t, where", " // t is \"num\", \"string\", \"keyword\", etc.", " sym.kind == t", "}", "", "method acceptKeyword (kw) {", " if (sym.isKeyword.not) then { return false }", " def v = sym.value", " if (v == kw) then { return true }", " return false", "}", "", "method acceptKeyword (kw1) or (kw2) {", " if (sym.isKeyword.not) then { return false }", " def v = sym.value", " if (v == kw1) then { return true }", " if (v == kw2) then { return true }", " return false", "}", "", "method acceptKeyword (kw1) or (kw2) or (kw3) {", " if (sym.isKeyword.not) then { return false }", " def v = sym.value", " if (v == kw1) then { return true }", " if (v == kw2) then { return true }", " if (v == kw3) then { return true }", " return false", "}", "", "method skipSeparators {", " while { sym.isSeparator } do { next }", "}", "", "method acceptArgument {", " // True if the current token can start an argument to a request", " if (sym.isString) then { return true }", " if (sym.isNum) then { return true }", " if (sym.isLBrace) then { return true }", " if (sym.isLSquare) then { return true }", " if (sym.isIdentifier) then {", " def symValue = sym.value", " return (symValue == \"true\") || (symValue == \"false\")", " }", " return false", "}", "", "method successfulParse (aParsingBlock) {", " // returns true if executing aParsingBlock parses at least one value.", " def sz = values.size", " aParsingBlock.apply", " values.size != sz", "}", "method unsuccessfulParse (aParsingBlock) {", " // returns true if executing aParsingBlock fails to parse any values.", " def sz = values.size", " aParsingBlock.apply", " values.size == sz", "}", "method pushNum {", " // Push the current token onto the output stack as a number", " var o := ast.numeral(sym.value)", " values.push(o)", " next", " return o", "}", "", "method pushString {", " // Push the current token onto the output stack as a string", " var o := ast.stringLiteral(sym.value)", " o.end := line (sym.line) column (sym.endCol)", " values.push(o)", " next", " return o", "}", "", "method pushIdentifier {", " // Push the current token onto the output stack as an identifier.", " // false means that this identifier has not yet been annotated with a dtype.", " util.setPosition(sym.line, sym.column)", " def o = if (sym.value == \"_\") then {", " ast.wildcardIdentifier(false)", " } else {", " ast.identifier(sym.value, false)", " }", " values.push(o)", " next", " return o", "}", "", "method checkAnnotation(ann) {", " if (ann.isCall) then {", " for (ann.parts) do {p->", " for (p.args) do {a->", " if ((a.isIdentifier) && {false != a.dtype}) then {", " var tok := sym", " // Look back from the current token to try and find the tokens that cause this error.", " while {tok.value != \":\"} do { tok := tok.prev }", " def suggestion = errormessages.suggestion.new", " suggestion.deleteTokenRange(tok, tok.next)leading(true)trailing(false)", " errormessages.syntaxError(\"an argument to an annotation cannot have a type.\")", " atRange(tok.line, tok.column, tok.next.endCol)", " withSuggestion(suggestion)", " }", " }", " }", " }", " ann", "}", "method doannotation {", " if (acceptKeyword \"is\" .not) then {", " return false", " }", " next", " def anns = ast.noAnnotations", " if (unsuccessfulParse {expression(noBlocks)}) then {", " errorMissingAnnotation", " }", " while {sym.isComma} do {", " anns.add(checkAnnotation(values.pop))", " next", " if (unsuccessfulParse {expression(noBlocks)}) then {", " errorMissingAnnotation", " }", " }", " anns.add(checkAnnotation(values.pop))", " anns", "}", "", "method errorMissingAnnotation {", " def suggestions = list [ ]", " var suggestion := errormessages.suggestion.new", " def nextTok = findNextValidToken [\"assignment\"]", " if (nextTok == sym) then {", " suggestion.insert(\" «annotation»\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)leading(true)trailing(false)with(\" «annotation»\")", " }", " suggestions.push(suggestion)", " suggestion := errormessages.suggestion.new", " suggestion.deleteTokenRange(lastToken, nextTok.prev)leading(true)trailing(false)", " suggestions.push(suggestion)", " errormessages.syntaxError(\"one or more annotations separated by commas must follow 'is'.\")", " atRange(lastToken.line, lastToken.column, lastToken.endCol)", " withSuggestions(suggestions)", "}", "", "method typeterm {", " if (sym.isIdentifier) then {", " pushIdentifier", " generic", " dotrest(noBlocks)", " } elseif {acceptKeyword \"outer\"} then {", " doouter", " skipSeparators", " if (! sym.isDot) then {", " values.pop", " // `outer` without a following `.method` is not a valid type", " } else {", " dotrest(noBlocks)", " }", " } elseif {acceptKeyword \"self\"} then {", " doself", " if (! sym.isDot) then {", " values.pop", " // `outer` without a following `.method` is not a valid type", " } else {", " dotrest(noBlocks)", " }", " } elseif {acceptKeyword \"interface\"} then {", " interfaceLiteral", " } elseif {acceptKeyword \"Unknown\"} then {", " values.push(ast.unknownLiteral)", " next", " } elseif {acceptKeyword \"Self\"} then {", " values.push(ast.selfTypeLiteral)", " next", " } elseif {acceptKeyword \"...\"} then {", " values.push(ast.ellipsis)", " next", " }", "}", "", "method typeexpression {", " var sz := values.size", " if (sym.isLParen) then {", " def prevStatementToken = statementToken", " statementToken := sym", " next", " if (unsuccessfulParse {typeexpression}) then {", " def suggestion = errormessages.suggestion.new", " def nextTok = findNextValidToken [\"rparen\"]", " if (nextTok == sym) then {", " suggestion.insert(\"«type expression»\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev) leading (true)", " trailing(false) with \"«type expression»\"", " }", " errormessages.syntaxError \"parentheses must contain a valid type expression.\"", " atPosition(sym.line, sym.column) withSuggestion(suggestion)", " }", " if (sym.kind != \"rparen\") then {", " checkBadOperators", " def suggestion = errormessages.suggestion.new", " suggestion.insert(\")\")afterToken(lastToken)", " errormessages.syntaxError \"a type expression beginning with a '(' must end with a ')'.\"", " atRange(lastToken.line, lastToken.column, lastToken.endCol)", " withSuggestion(suggestion)", " }", " statementToken := prevStatementToken", " next", " } else {", " typeterm", " }", " if (values.size > sz) then {", " dotrest(noBlocks)", " typeexpressionrest", " }", " // TODO: check that the expression doesn't contain arbitrary requests or var references.", " // This has to happen in the identifier resolution phase.", "}", "", "method newIf(cond, thenList, elseList) {", " def thenBlock = ast.block(sequence.empty, thenList)", " def elseBlock = ast.block(sequence.empty, elseList)", " ast.ifExpr(cond, thenBlock, elseBlock)", "}", "", "method reportSyntaxError(message) before (expectedTokens) {", " def suggestions = list [ ]", " var suggestion := errormessages.suggestion.new", " def nextTok = findNextValidToken (expectedTokens)", " if (nextTok == sym) then {", " suggestion.insert(\" «expression»\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)leading(true)trailing(false)with(\" «expression»\")", " }", " suggestions.push(suggestion)", " suggestion := errormessages.suggestion.new", " suggestion.deleteTokenRange(lastToken, nextTok.prev)leading(true)trailing(false)", " suggestions.push(suggestion)", " errormessages.syntaxError(message)", " atPosition(sym.line, sym.column)", " withSuggestions(suggestions)", "}", "", "method reportMissingArrow {", " def suggestion = errormessages.suggestion.new", " if ((sym.isAssignment) || (sym.value == \"=\")) then {", " suggestion.replaceToken(sym)with(\"->\")", " } else {", " suggestion.insert(\" ->\")afterToken(lastToken)", " }", " errormessages.syntaxError(\"in a block with parameters, the parameters must be followed by '->'\")", " atPosition(sym.line, sym.column) withSuggestion(suggestion)", "}", "", "method reportBadRhs {", " // a bind symbol := was not followed by a valid expression.", "", " def suggestions = list [ ]", " var suggestion := errormessages.suggestion.new", " def nextTok = findNextValidToken [\"rbrace\"]", " if (nextTok == sym) then {", " suggestion.insert(\" «expression»\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)leading(true)trailing(false)with(\" «expression»\")", " }", " suggestions.push(suggestion)", " suggestion := errormessages.suggestion.new", " suggestion.deleteTokenRange(lastToken, nextTok.prev)leading(true)trailing(false)", " suggestions.push(suggestion)", " errormessages.syntaxError(\"a valid expression must follow ':='.\")", " atPosition(sym.line, sym.column) withSuggestions(suggestions)", "}", "", "method block {", " // Parses a block. Since a block is (a) treated as a statement, and", " // (b) may have statements inside, we save and restore the setting of the", " // global variables relevant to the statement context.", "", " if (sym.isLBrace) then {", " def btok = sym", " next", " skipSeparators", " def oldStatementToken = statementToken", " statementToken := sym", " var isMatchingBlock := false", "", " // a block may start with or without parameters. We assume that", " // parameters are present, parse the first expression, and then check.", " // If it wasn't a parameter, we back-up the parse position.", " def savedPosition = saveParsePosition", " def params = blockParameters", " if (params.isEmpty) then {", " restoreParsePosition(savedPosition)", " }", "", " def blockNode = blockBody (params) beginningWith (btok)", " values.push(blockNode)", " statementToken := oldStatementToken", " }", "}", "", "method blockParameters {", " // parse all the parameters of this block, and return them as a", " // collection of identifier nodes.", " def params = list [ ]", " while {blockParameter(params)} do {", " if (sym.isArrow) then {", " next", " skipSeparators", " return params", " }", " if (sym.isComma) then {", " next", " } else {", " reportMissingArrow", " }", " }", " skipSeparators", " return params", "}", "", "method blockParameter(params) -> Boolean {", " // parse one parameter, if possible, push it onto params, and", " // return true. If the next expression is not a parameter, return false.", "", " var paramIsPattern := sym.isLParen", " // Parsing the expression ‹(a)› will return an identifierNode‹a› .", " // Checking for a paren lets us distinguish parameter from pattern.", " if (successfulParse {expression(blocksOK)}) then {", " if (sym.isComma || sym.isArrow || sym.isColon) then {", " // we have found a parameter", " var thisParam := values.pop", " if (paramIsPattern || thisParam.isIdentifier.not) then {", " paramIsPattern := true", " thisParam := ast.wildcardIdentifier(thisParam)", " // put the pattern in the type field", " }", " thisParam.isBindingOccurrence := true", " thisParam.isParameter := true", " if (paramIsPattern && sym.isColon) then {", " reportSyntaxError(\"a block parameter that's an expression is assumed to mean \" ++", " \"_:‹expression›, and so cannot be followed by a colon\")", " before [\"arrow\", \"comma\"]", " }", " if (sym.isColon) then {", " // We allow an expression for v: <PatternExpression>", " next", " if (successfulParse {expression(blocksOK)} .not) then {", " reportSyntaxError \"a block parameter must have a pattern or type expression after the ':'.\" before [\"arrow\", \"rbrace\"]", " }", " thisParam.dtype := values.pop", " }", " params.push(thisParam)", " return true", " } else {", " // we just parsed the first expression in the block", " return false", " }", " } else {", " return false // we didn't parse anything", " }", "}", "", "method blockBody(params) beginningWith (btok) {", " // returns a block AST node. params is the list of parameters,", " // which may be empty, and btok the lbrace that started the block.", " // The module variable sym is the first token in the body, and lastToken", " // is the preceeding lbrace that started the block, or the arrow that", " // terminated the parameter list (if there was one),", " // or the comment that appears after the lbrace, if there was one.", "", " def originalValues = values", " values := list []", " while {sym.isRBrace.not} do {", " // Take the body of the block", " if (unsuccessfulParse {statement}) then {", " def suggestion = errormessages.suggestion.new", " suggestion.insert \"}\" afterToken (lastToken)", " errormessages.syntaxError \"a block must end with a '}'.\"", " atPosition(sym.line, sym.column) withSuggestion(suggestion)", " }", " separator", " }", " def etok = sym // the closing rbrace", " next", " def body = values", " values := originalValues", " return ast.block(params, body).setPositionFrom(btok)", "}", "", "", "// Accept an \"if\" statement. This is a special syntactic case, rather", "// than just a call with a multi-part method name - it might be possible", "// to change that and compensate later on.", "method doif {", " if (sym.isIdentifier && (sym.value == \"if\")) then {", " def btok = sym", " next", " def opener = if (sym.isLParen || {sym.isLBrace})", " then { sym.value } else { \"-missing-\" }", " def closer = if (opener == \"(\") then { \")\" }", " elseif { opener == \"\\{\" } then { \"\\}\" }", " else { \"-nothing-\" }", " if (opener == \"-missing-\") then {", " def suggestion = errormessages.suggestion.new", " // Look ahead for a rparen or then.", " def nextTok = findNextToken { t ->", " (t.line == btok.line) && ((t.isRParen) ||", " (t.isRBrace) || (t.isLBrace) ||", " ((t.isIdentifier) && (t.value == \"then\")))", " }", " if (false == nextTok) then {", " suggestion.insert(\" («condition») then \\{\")afterToken(btok)", " } elseif { nextTok.isRParen } then {", " if (nextTok == sym) then {", " suggestion.insert(\"(«condition»\")beforeToken(sym)", " } else {", " suggestion.insert(\"(\")beforeToken(sym)", " }", " } elseif { nextTok.isLBrace } then {", " if (nextTok == sym) then {", " suggestion.insert(\" («condition») then\")afterToken(btok)", " } else {", " suggestion.insert(\"(\")beforeToken(sym)", " suggestion.insert(\") then\")afterToken(nextTok.prev)andTrailingSpace(true)", " }", " } elseif { nextTok.isIdentifier } then {", " if (nextTok == sym) then {", " suggestion.insert(\"(«condition») \")beforeToken(sym)", " } else {", " suggestion.insert(\"(\")beforeToken(sym)", " suggestion.insert(\")\")afterToken(nextTok.prev)andTrailingSpace(true)", " }", " }", " errormessages.syntaxError(\"an if statement must have a condition \" ++", " \"in parentheses or braces after the 'if'.\")", " atPosition(sym.line, sym.column) withSuggestion(suggestion)", " }", " next", " if (unsuccessfulParse {expression(blocksOK)}) then {", " def suggestion = errormessages.suggestion.new", " // Look ahead for a rparen.", " var nextTok := findNextToken { t -> (t.line == lastToken.line) && (t.isRParen) }", " if (false == nextTok) then {", " nextTok := findNextValidToken [\"rparen\"]", " if (nextTok == sym) then {", " suggestion.insert(\"«expression») then \\{\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)", " leading(true)trailing(false)with(\"«expression») then \\{\")", " }", " errormessages.syntaxError(\"an if statement must have a \" ++", " \"condition in parentheses or braces after the 'if'.\")", " atPosition(sym.line, sym.column)", " withSuggestion(suggestion)", " } else {", " if (nextTok == sym) then {", " suggestion.insert(\"«expression»\")afterToken(lastToken)", " errormessages.syntaxError(\"an if statement must have a \" ++", " \"condition in parentheses or braces after the 'if'.\")", " atPosition(sym.line, sym.column)", " withSuggestion(suggestion)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)", " leading(false)trailing(true)with(\"«expression»\")", " errormessages.syntaxError(\"an if statement must have a \" ++", " \"condition in parentheses or braces after the 'if'.\")", " atRange(sym.line, sym.column, nextTok.column - 1)", " withSuggestion(suggestion)", " }", " }", " }", " if (sym.value != closer) then {", " checkBadOperators", " def suggestion = errormessages.suggestion.new", " suggestion.insert(\")\")afterToken(lastToken)", " errormessages.syntaxError(\"an expression beginning with a \"++", " \"'{opener}' must end with a '{closer}'.\")", " atPosition(lastToken.line, lastToken.column + lastToken.size)", " withSuggestion(suggestion)", " }", " next", " var cond := values.pop", " var body := list []", "", " var elseblock := list []", " var curelse := elseblock", " // These two variables are for else/elseif handling. An 'elseif' is", " // turned into nested 'if' statements for the AST; `curelse` points", " // to the most deeply-nested of those (where any eventual \"else\"", " // blocks will go). `elseblock` contains the statements of the", " // top-level 'else' block --- if there are any 'elseif's, that top-", " // level 'else' will comprise just one statement: another if.", " var v", " if (sym.isIdentifier && (sym.value == \"then\")) then {", " next", " if (sym.kind != \"lbrace\") then {", " def suggestion = errormessages.suggestion.new", " def closingBrace = findClosingBrace(btok, true)", " if (closingBrace.found.not) then {", " if (closingBrace.tok == lastToken) then {", " suggestion.replaceToken(lastToken)leading(false)trailing(true)with(\"then \\{}\")", " } else {", " suggestion.addLine(closingBrace.tok.line + 0.1, \"}\")", " suggestion.replaceToken(lastToken)leading(false)trailing(true)with(\"then \\{\")", " }", " } else {", " suggestion.replaceToken(lastToken)leading(false)trailing(true)with(\"then \\{\")", " }", " errormessages.syntaxError(\"an if statement must have a '\\{' after the 'then'.\")atPosition(", " lastToken.line, lastToken.column + lastToken.size)withSuggestion(suggestion)", " }", " next", " while {sym.isRBrace.not} do {", " if (unsuccessfulParse {statement}) then {", " def suggestion = errormessages.suggestion.new", " def closingBrace = findClosingBrace(btok, false)", " if (closingBrace.found.not) then {", " if (closingBrace.tok == lastToken) then {", " suggestion.insert(\"}\")afterToken(lastToken)", " } else {", " suggestion.addLine(closingBrace.tok.line + 0.1, \"}\")", " }", " }", " suggestion.deleteToken(sym)", " errormessages.syntaxError \"the then clause of an if statement must end with a '}'\"", " atPosition(sym.line, sym.column)", " withSuggestion(suggestion)", " }", " separator", " body.push(values.pop)", " }", " next", " var econd", " var eif", " var newelse", " var ebody", " while {sym.isIdentifier && (sym.value == \"elseif\")} do {", " // Currently, the parser just accepts arbitrarily many", " // \"elseifs\", turning them into ifs inside the else.", " // TODO: allow blocks after elseif to contain a sequence of expressions.", " statementToken := sym", " next", " if (sym.isLBrace.not) then {", " def suggestion = errormessages.suggestion.new", " // Look ahead for a rbrace or then.", " def nextTok = findNextToken { t ->", " (t.line == statementToken.line)", " && ((t.isRBrace || t.isLBrace)", " || (t.isIdentifier && (t.value == \"then\"))) }", " if (false == nextTok) then {", " suggestion.insert(\" \\{ «expression» \\} then \\{\")afterToken(statementToken)", " } elseif { nextTok.isRBrace } then {", " if (nextTok == sym) then {", " suggestion.insert(\"\\{ «expression» \\}\")beforeToken(sym)", " } else {", " suggestion.insert(\"\\{ \")beforeToken(sym)", " }", " } elseif { nextTok.isLBrace } then {", " if (nextTok == sym) then {", " suggestion.insert(\" \\{ «expression» \\} then\")afterToken(statementToken)", " } else {", " suggestion.insert(\"\\{ \")beforeToken(sym)", " suggestion.insert(\" \\} then\")afterToken(nextTok.prev)andTrailingSpace(true)", " }", " } elseif { nextTok.isIdentifier } then {", " if (nextTok == sym) then {", " suggestion.insert(\"\\{ «expression» \\} \")beforeToken(sym)", " } else {", " suggestion.insert(\"\\{ \")beforeToken(sym)", " suggestion.insert(\" \\}\")afterToken(nextTok.prev)andTrailingSpace(true)", " }", " }", " errormessages.syntaxError(\"an elseif statement must have a \" ++", " \"condition in braces after the 'elseif'.\")", " atPosition(sym.line, sym.column)", " withSuggestion(suggestion)", " }", " next", " if (unsuccessfulParse {expression(blocksOK)}) then {", " def suggestion = errormessages.suggestion.new", " // Look ahead for a rbrace or then.", " var nextTok := findNextToken { t ->", " (t.line == lastToken.line) && (t.isRBrace)}", " if (false == nextTok) then {", " nextTok := findNextValidToken [\"rbrace\"]", " if (nextTok == sym) then {", " suggestion.insert(\"«expression» \\} then \\{\")afterToken(lastToken)", " } else {", " suggestion.replaceTokenRange(sym, nextTok.prev)leading(true)trailing(false)with(\"«expression» \\} then \\{\")", " }", " errormessages.syntaxError(\"an elseif clause must have an expression in braces after the 'elseif'.\")atPosition(", " sym.line, sym.column)withSuggestion(suggestion)", " } else {", " if (nextTok == sym) then {", " suggestion.insert(\"«expression»\")afterToken(lastToken)", " errormessages.syntaxError(\"an elseif clause must have an expression in braces after the 'elseif'.\")atPosition(", " sym.line, sym.column)withSuggestion(suggestion)", " } else {", " //checkInvalidExpression", " suggestion.replaceTokenRange(sym, nextTok.prev)leading(false)trailing(true)with(\"«expression»\")", " errormessages.syntaxError(\"(4) an elseif statement must have an expression in braces after the 'elseif'.\")atRange(", " sym.line, sym.column, nextTok.column - 1)withSuggestion(suggestion)", " }", " }", " }", " if (sym.value != \"\\}\") then {", " checkBadOperators", " def suggestion = errormessages.suggestion.new", " suggestion.insert \"}\" afterToken (lastToken)", " errormessages.syntaxError(\"a condition beginning with a \" ++", " \"'\\{' must end with a '\\}'.\")", " atPosition(lastToken.line, lastToken.column + lastToken.size)", " withSuggestion(suggestion)", " }", " next", " econd := values.pop", " if (sym.isIdentifier && (sym.value == \"then\")) then {", " next", " ebody := list []", " } else {", " def suggestion = errormessages.suggestion.new", " if (sym.isLBrace) then {", " def closingBrace = findClosingBrace(statementToken, false)", " if (closingBrace.found.not) then {", "