Skip to content

Commit

Permalink
Parser: fix expr error handling; refactor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Jun 8, 2023
1 parent 2154a8f commit 09fd119
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 73 deletions.
161 changes: 89 additions & 72 deletions src/parser/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,90 +11,107 @@ describe('parser', () => {
return { tree: compactNode(tree), errors: p.errors }
}

it('parse fn-def empty', () => {
const { tree, errors } = parse('fn main() {}')
expect(errors.length).toEqual(0)
expect(tree).toEqual({
'module': [{
'statement': [{
'fn-def': [
{ 'fn-keyword': 'fn' },
{ 'identifier': 'main' },
{ 'o-paren': '(' }, { 'c-paren': ')' },
{ 'block': [{ 'o-brace': '{' }, { 'c-brace': '}' }] }
]
describe('parse fn-def', () => {
it('empty', () => {
const { tree, errors } = parse('fn main() {}')
expect(errors.length).toEqual(0)
expect(tree).toEqual({
'module': [{
'statement': [{
'fn-def': [
{ 'fn-keyword': 'fn' },
{ 'identifier': 'main' },
{ 'o-paren': '(' }, { 'c-paren': ')' },
{ 'block': [{ 'o-brace': '{' }, { 'c-brace': '}' }] }
]
}]
}]
}]
})
})
})

describe('parse fn-def', () => {
it('miss identifier', () => {
const { errors } = parse('let = 4')
expect(errors.length).toEqual(1)
expect(errors[0]).toEqual({
'expected': ['identifier'],
'got': {
'kind': 'equals',
'location': {
'end': 4,
'start': 4
},
'value': '='
}
})
})
})

it('parse if-expr', () => {
const { tree, errors } = parse('if a { b } else { c }')
expect(errors.length).toEqual(0)
expect(tree).toEqual({
'module': [{
'statement': [{
'expr': [{
'sub-expr': [{
'operand': [{
'if-expr': [
{ 'if-keyword': 'if' },
{ 'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'a' }] }] }] },
{
'block': [
{ 'o-brace': '{' },
{
'statement': [{
'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'b' }] }] }]
}]
},
{ 'c-brace': '}' }
]
},
{ 'else-keyword': 'else' },
{
'block': [
{ 'o-brace': '{' },
{
'statement': [{
'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'c' }] }] }]
}]
},
{ 'c-brace': '}' }
]
}
]
describe('parse if-expr', () => {
it('general', () => {
const { tree, errors } = parse('if a { b } else { c }')
expect(errors.length).toEqual(0)
expect(tree).toEqual({
'module': [{
'statement': [{
'expr': [{
'sub-expr': [{
'operand': [{
'if-expr': [
{ 'if-keyword': 'if' },
{ 'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'a' }] }] }] },
{
'block': [
{ 'o-brace': '{' },
{
'statement': [{
'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'b' }] }] }]
}]
},
{ 'c-brace': '}' }
]
},
{ 'else-keyword': 'else' },
{
'block': [
{ 'o-brace': '{' },
{
'statement': [{
'expr': [{ 'sub-expr': [{ 'operand': [{ 'identifier': 'c' }] }] }]
}]
},
{ 'c-brace': '}' }
]
}
]
}]
}]
}]
}]
}]
}]
})
})
})

it('parse var-def miss identifier', () => {
const { errors } = parse('let = 4')
expect(errors.length).toEqual(1)
expect(errors[0]).toEqual({
'expected': ['identifier'],
'got': {
'kind': 'equals',
'location': {
'end': 4,
'start': 4
},
'value': '='
}
it('mismatch paren', () => {

const { errors } = parse('if a { b) }')
expect(errors.length).toEqual(1)
expect(errors[0]).toEqual({
'expected': [],
'got': { 'kind': 'c-paren', 'location': { 'end': 8, 'start': 8 }, 'value': ')' },
'message': 'expected operand'
})
})
})

it('parse if-expr mismatch paren', () => {
const { errors } = parse('if a { b) }')
expect(errors.length).toEqual(1)
expect(errors[0]).toEqual({
'expected': [],
'got': { 'kind': 'c-paren', 'location': { 'end': 8, 'start': 8 }, 'value': ')' },
'message': 'expected operand'
it('duplicate else clause', () => {
const { errors } = parse('if a { b } else { c } else { d }')
expect(errors.length).toEqual(3)
expect(errors[0]).toEqual({
'expected': [],
'got': { 'kind': 'else-keyword', 'location': { 'end': 25, 'start': 22 }, 'value': 'else' },
'message': 'expected statement'
})
})
})

Expand Down
4 changes: 3 additions & 1 deletion src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ const parseTodo = (parser: Parser): void => {

const prefixOpFirstTokens: TokenKind[] = ['excl', 'minus', 'period', 'plus']
const postfixOpFirstTokens: TokenKind[] = ['o-paren']
const infixOpFirstTokens: TokenKind[] = ['ampersand', 'asterisk', 'c-angle', 'caret', 'equals', 'excl', 'minus',
'o-angle', 'percent', 'period', 'pipe', 'plus', 'slash']
const exprFirstTokens: TokenKind[] = ['char', 'identifier', 'if-keyword', 'number', 'o-paren', 'string', ...prefixOpFirstTokens]
const statementFirstTokens: TokenKind[] = ['let-keyword', 'fn-keyword', 'return-keyword', 'type-keyword', ...exprFirstTokens]

Expand Down Expand Up @@ -347,7 +349,7 @@ const parseReturnStmt = (parser: Parser): void => {
const parseExpr = (parser: Parser): void => {
const mark = parser.open()
parseSubExpr(parser)
while (!parser.atAny(exprFollowTokens) && !parser.eof()) {
while (parser.atAny(infixOpFirstTokens) && !parser.eof()) {
parseInfixOp(parser)
parseSubExpr(parser)
}
Expand Down

0 comments on commit 09fd119

Please sign in to comment.