Add try expressions

pull/101/head
Max Brunsfeld 2018-02-22 17:06:29 +07:00
parent a8b0acb96c
commit 5a17adfe39
5 changed files with 56312 additions and 30491 deletions

@ -133,6 +133,29 @@ def other() {
(block (identifier))
(call_expression (identifier) (arguments))))))
===============================
Try expressions
===============================
def main() {
try a() finally depth -= 1
try b() catch { case e => println(e) }
}
---
(compilation_unit
(function_definition
(identifier)
(parameters)
(block
(try_expression
(call_expression (identifier) (arguments))
(finally_clause (infix_expression (identifier) (operator_identifier) (number))))
(try_expression
(call_expression (identifier) (arguments))
(catch_clause (case_block (case_clause (identifier) (call_expression (identifier) (arguments (identifier))))))))))
===============================
Match expressions
===============================

@ -0,0 +1,108 @@
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package ast.parser
import javac._
/** An nsc sub-component.
*/
abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with Scanners with JavaParsers with JavaScanners {
import global._
val phaseName = "parser"
def newPhase(prev: Phase): StdPhase = new ParserPhase(prev)
abstract class MemberDefTraverser extends Traverser {
def onMember(defn: MemberDef): Unit
private var depth: Int = 0
private def lower[T](body: => T): T = {
depth += 1
try body finally depth -= 1
}
def currentDepth = depth
/** Prune this tree and all trees beneath it. Can be overridden. */
def prune(md: MemberDef): Boolean = (
md.mods.isSynthetic
|| md.mods.isParamAccessor
|| nme.isConstructorName(md.name)
|| (md.name containsName nme.ANON_CLASS_NAME)
)
override def traverse(t: Tree): Unit = t match {
case md: MemberDef if prune(md) =>
case md @ PackageDef(_, stats) => traverseTrees(stats)
case md: ImplDef => onMember(md) ; lower(traverseTrees(md.impl.body))
case md: ValOrDefDef => onMember(md) ; lower(traverse(md.rhs))
case _ => super.traverse(t)
}
}
class MemberPosReporter(unit: CompilationUnit) extends MemberDefTraverser {
private var outputFn: MemberDef => String = outputForScreen
val path = unit.source.file.path
// If a single line, outputs the line; if it spans multiple lines
// outputs NN,NN with start and end lines, e.g. 15,25.
def outputPos(md: MemberDef): String = {
val pos = md.pos
val start = pos.focusStart.line
val end = pos.focusEnd.line
if (start == end) "" + start else s"$start,$end"
}
def outputForSed(md: MemberDef): String = {
val pos_s = "%-12s" format outputPos(md) + "p"
s"$pos_s $path # ${md.keyword} ${md.name}"
}
def outputForScreen(md: MemberDef): String = {
val pos_s = "%-20s" format " " * currentDepth + outputPos(md)
s"$pos_s ${md.keyword} ${md.name}"
}
def onMember(md: MemberDef) = println(outputFn(md))
// It recognizes "sed" and "anything else".
def show(style: String) {
if (style == "sed") {
outputFn = outputForSed
traverse(unit.body)
}
else {
outputFn = outputForScreen
println(path)
traverse(unit.body)
}
println("")
}
}
private def initialUnitBody(unit: CompilationUnit): Tree = {
if (unit.isJava) newJavaUnitParser(unit).parse()
else if (currentRun.parsing.incompleteHandled) newUnitParser(unit).parse()
else newUnitParser(unit).smartParse()
}
class ParserPhase(prev: Phase) extends StdPhase(prev) {
override val checkable = false
override val keepsTypeParams = false
def apply(unit: CompilationUnit) {
informProgress("parsing " + unit)
// if the body is already filled in, don't overwrite it
// otherwise compileLate is going to overwrite bodies of synthetic source files
if (unit.body == EmptyTree)
unit.body = initialUnitBody(unit)
if (settings.Yrangepos && !reporter.hasErrors)
validatePositions(unit.body)
if (settings.Ymemberpos.isSetByUser)
new MemberPosReporter(unit) show (style = settings.Ymemberpos.value)
}
}
}

@ -366,6 +366,7 @@ module.exports = grammar({
_expression: $ => choice(
$.if_expression,
$.match_expression,
$.try_expression,
$.call_expression,
$.generic_function,
$.assignment_expression,
@ -399,6 +400,17 @@ module.exports = grammar({
$.case_block
),
try_expression: $ => prec.right(seq(
'try',
$._expression,
optional($.catch_clause),
optional($.finally_clause)
)),
catch_clause: $ => prec.right(seq('catch', $.case_block)),
finally_clause: $ => prec.right(seq('finally', $._expression)),
case_block: $ => choice(
prec(-1, seq('{', '}')),
seq('{', repeat1($.case_clause), '}')

79
src/grammar.json vendored

@ -1703,6 +1703,10 @@
"type": "SYMBOL",
"name": "match_expression"
},
{
"type": "SYMBOL",
"name": "try_expression"
},
{
"type": "SYMBOL",
"name": "call_expression"
@ -1824,6 +1828,81 @@
}
]
},
"try_expression": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "try"
},
{
"type": "SYMBOL",
"name": "_expression"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "catch_clause"
},
{
"type": "BLANK"
}
]
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "finally_clause"
},
{
"type": "BLANK"
}
]
}
]
}
},
"catch_clause": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "catch"
},
{
"type": "SYMBOL",
"name": "case_block"
}
]
}
},
"finally_clause": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "finally"
},
{
"type": "SYMBOL",
"name": "_expression"
}
]
}
},
"case_block": {
"type": "CHOICE",
"members": [

86581
src/parser.c vendored

File diff suppressed because it is too large Load Diff