diff --git a/examples/numbers.pork b/examples/numbers.pork index 19f0834..1ed2e9a 100644 --- a/examples/numbers.pork +++ b/examples/numbers.pork @@ -1,4 +1,5 @@ export func main() { let pi = 3.141592653589793 println(pi) + } diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/ParseError.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/ParseError.kt index 43ad464..e6004a2 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/ParseError.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/ParseError.kt @@ -1,3 +1,3 @@ package gay.pizza.pork.parser -class ParseError(val error: String) : RuntimeException(error) +open class ParseError(val error: String) : RuntimeException(error) diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt index 3532d73..56114c5 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/Parser.kt @@ -16,7 +16,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : Block(items) } - override fun parseExpression(): Expression { + override fun parseExpression(): Expression = guarded { val token = peek() val expression = when (token.type) { TokenType.NumberLiteral -> parseNumberLiteral() @@ -37,7 +37,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : TokenType.None -> parseNoneLiteral() else -> { - throw gay.pizza.pork.parser.ParseError( + throw ParseError( "Failed to parse token: ${token.type} '${token.text}' as" + " expression (index ${source.currentIndex})" ) @@ -45,7 +45,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } if (expression is SymbolReference && peek(TokenType.Equals)) { - return guarded { + return@guarded guarded { attribution.adopt(expression) expect(TokenType.Equals) val value = parseExpression() @@ -53,7 +53,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } } - return if (peek( + return@guarded if (peek( TokenType.Plus, TokenType.Minus, TokenType.Multiply, @@ -138,7 +138,7 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : return modifiers } - fun maybeParseDefinition(): Definition? { + private fun maybeParseDefinition(): Definition? { try { storedDefinitionModifiers = parseDefinitionModifiers() val token = peek() @@ -152,19 +152,19 @@ class Parser(source: TokenSource, attribution: NodeAttribution) : } } - override fun parseDeclaration(): Declaration { + override fun parseDeclaration(): Declaration = guarded { val token = peek() - return when (token.type) { + return@guarded when (token.type) { TokenType.Import -> parseImportDeclaration() - else -> throw gay.pizza.pork.parser.ParseError( + else -> throw ParseError( "Failed to parse token: ${token.type} '${token.text}' as" + " declaration (index ${source.currentIndex})" ) } } - override fun parseDefinition(): Definition { - return maybeParseDefinition() ?: throw ParseError("Unable to parse definition") + override fun parseDefinition(): Definition = guarded { + maybeParseDefinition() ?: throw ParseError("Unable to parse definition") } override fun parseDoubleLiteral(): DoubleLiteral = guarded { diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt index ee7cdee..d5b959f 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/ParserBase.kt @@ -4,8 +4,6 @@ import gay.pizza.pork.ast.Node import gay.pizza.pork.ast.NodeParser abstract class ParserBase(val source: TokenSource, val attribution: NodeAttribution) : NodeParser { - open class ParseError(error: String) : RuntimeException(error) - class ExpectedTokenError(got: Token, vararg expectedTypes: TokenType) : ParseError( "Expected one of ${expectedTypes.joinToString(", ")}" + " but got type ${got.type} '${got.text}'" diff --git a/parser/src/main/kotlin/gay/pizza/pork/parser/ParserHelpers.kt b/parser/src/main/kotlin/gay/pizza/pork/parser/ParserHelpers.kt index c7c7377..e308741 100644 --- a/parser/src/main/kotlin/gay/pizza/pork/parser/ParserHelpers.kt +++ b/parser/src/main/kotlin/gay/pizza/pork/parser/ParserHelpers.kt @@ -23,7 +23,7 @@ internal object ParserHelpers { TokenType.GreaterEqual -> InfixOperator.GreaterEqual TokenType.And -> InfixOperator.BooleanAnd TokenType.Or -> InfixOperator.BooleanOr - else -> throw ParserBase.ParseError("Unknown Infix Operator") + else -> throw ParseError("Unknown Infix Operator") } fun convertPrefixOperator(token: Token): PrefixOperator = when (token.type) { @@ -31,12 +31,12 @@ internal object ParserHelpers { TokenType.Plus -> PrefixOperator.UnaryPlus TokenType.Minus -> PrefixOperator.UnaryMinus TokenType.Tilde -> PrefixOperator.BinaryNot - else -> throw ParserBase.ParseError("Unknown Prefix Operator") + else -> throw ParseError("Unknown Prefix Operator") } fun convertSuffixOperator(token: Token): SuffixOperator = when (token.type) { TokenType.PlusPlus -> SuffixOperator.Increment TokenType.MinusMinus -> SuffixOperator.Decrement - else -> throw ParserBase.ParseError("Unknown Suffix Operator") + else -> throw ParseError("Unknown Suffix Operator") } } diff --git a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/PsiBuilderMarkAttribution.kt b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/PsiBuilderMarkAttribution.kt index fc7a836..733f63b 100644 --- a/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/PsiBuilderMarkAttribution.kt +++ b/support/pork-idea/src/main/kotlin/gay/pizza/pork/idea/PsiBuilderMarkAttribution.kt @@ -4,14 +4,17 @@ import com.intellij.lang.PsiBuilder import gay.pizza.pork.ast.Node import gay.pizza.pork.parser.ParseError import gay.pizza.pork.parser.ParserNodeAttribution +import java.util.IdentityHashMap class PsiBuilderMarkAttribution(val builder: PsiBuilder) : ParserNodeAttribution() { + private val map = IdentityHashMap() + override fun guarded(block: () -> T): T { val marker = builder.mark() - try { + val result = try { val item = super.guarded(block) marker.done(PorkElementTypes.elementTypeFor(item.type)) - return item + item } catch (e: PsiBuilderTokenSource.BadCharacterError) { marker.error("Bad character.") while (!builder.eof()) { @@ -32,5 +35,10 @@ class PsiBuilderMarkAttribution(val builder: PsiBuilder) : ParserNodeAttribution } throw PorkParser.ExitParser() } + if (map[result] != null) { + marker.drop() + } + map[result] = result + return result } }