Skip to content

Commit

Permalink
Parser: more compact tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Jun 4, 2023
1 parent 80cb24f commit 0e1d8a8
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 149 deletions.
279 changes: 132 additions & 147 deletions src/parser/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,22 @@ describe('parser', () => {
const code = `let main = (): Unit {}`
const rule = parseToken(code)
expect(compactToken(rule!)).toEqual({
'name': 'program',
'nodes': [{
'name': 'statements',
'nodes': [{
'name': 'statement',
'nodes': [{
'name': 'variable-def',
'nodes': [
{ 'name': 'let-keyword', 'value': 'let' },
{ 'name': 'identifier', 'value': 'main' },
{ 'name': 'equals', 'value': '=' },
{
'name': 'expr',
'nodes': [{
'name': 'operand',
'nodes': [{
'name': 'function-expr',
'nodes': [
{ 'name': 'open-paren', 'value': '(' },
{ 'name': 'close-paren', 'value': ')' },
{ 'name': 'colon', 'value': ':' },
{
'name': 'type',
'nodes': [
{ 'name': 'identifier', 'value': 'Unit' }
]
},
{
'name': 'block',
'nodes': [
{ 'name': 'open-brace', 'value': '{' },
{ 'name': 'close-brace', 'value': '}' }
]
}
]
}]
'program': [{
'statements': [{
'statement': [{
'variable-def': [{ 'let-keyword': 'let' }, { 'identifier': 'main' }, { 'equals': '=' }, {
'expr': [{
'operand': [{
'function-expr': [
{ 'open-paren': '(' },
{ 'close-paren': ')' },
{ 'colon': ':' },
{ 'type': [{ 'identifier': 'Unit' }] },
{ 'block': [{ 'open-brace': '{' }, { 'close-brace': '}' }] }
]
}]
}
]
}]
}]
}]
}]
}]
Expand All @@ -68,141 +45,149 @@ describe('parser', () => {
it('parse unary-expr', () => {
const rule = parseToken('-3', 'expr')
expect(compactToken(rule!)).toEqual({
'name': 'expr',
'nodes': [
{
'name': 'prefix-op',
'nodes': [
{ 'name': 'minus', 'value': '-' }
]
},
{
'name': 'operand',
'nodes': [
{ 'name': 'number', 'value': '3' }
]
}]
'expr': [
{ 'prefix-op': [{ 'minus': '-' }] },
{ 'operand': [{ 'number': '3' }] }
]
})
})

it('parse function call', () => {
const rule = parseToken('foo(12)', 'expr')
expect(compactToken(rule!)).toEqual({
'name': 'expr', 'nodes': [{ 'name': 'operand', 'nodes': [{ 'name': 'identifier', 'value': 'foo' }] }, {
'name': 'postfix-op', 'nodes': [{
'name': 'call-op',
'nodes': [{ 'name': 'open-paren', 'value': '(' }, {
'name': 'args',
'nodes': [{
'name': 'expr',
'nodes': [{ 'name': 'operand', 'nodes': [{ 'name': 'number', 'value': '12' }] }]
}]
}, { 'name': 'close-paren', 'value': ')' }]
}]
}]
'expr': [
{ 'operand': [{ 'identifier': 'foo' }] },
{
'postfix-op': [{
'call-op': [
{ 'open-paren': '(' },
{ 'args': [{ 'expr': [{ 'operand': [{ 'number': '12' }] }] }] },
{ 'close-paren': ')' }
]
}]
}
]
})
})

it('parse expr1', () => {
const rule = parseToken('(foo(12) / 4)', 'expr')

const foo = { 'name': 'operand', 'nodes': [{ 'name': 'identifier', 'value': 'foo' }] }
const callOp = {
'name': 'postfix-op', 'nodes': [{
'name': 'call-op', 'nodes': [{ 'name': 'open-paren', 'value': '(' }, {
'name': 'args',
'nodes': [{
'name': 'expr',
'nodes': [{ 'name': 'operand', 'nodes': [{ 'name': 'number', 'value': '12' }] }]
}]
}, { 'name': 'close-paren', 'value': ')' }]
}]
}

const divOp = { 'name': 'infix-operator', 'nodes': [{ 'name': 'slash', 'value': '/' }] }
const op4 = {
'name': 'operand',
'nodes': [{ 'name': 'number', 'value': '4' }]
}
it('parse function-expr', () => {
const code = `(): Unit {}`
const rule = parseToken(code, 'expr')
expect(compactToken(rule!)).toEqual({
'name': 'expr', 'nodes': [{
'name': 'operand', 'nodes': [{ 'name': 'open-paren', 'value': '(' }, {
'name': 'expr',
'nodes': [foo, callOp, divOp, op4]
}, { 'name': 'close-paren', 'value': ')' }]
'expr': [{
'operand': [{
'function-expr': [
{ 'open-paren': '(' },
{ 'close-paren': ')' },
{ 'colon': ':' },
{ 'type': [{ 'identifier': 'Unit' }] },
{ 'block': [{ 'open-brace': '{' }, { 'close-brace': '}' }] }
]
}]
}]
})
})

xit('parse expr2', () => {
const rule = parseToken('(foo(12) / 4) * "str".ok()', 'expr')
it('parse method call', () => {
const rule = parseToken('"str".ok(4)', 'expr')
expect(compactToken(rule!)).toEqual({
'name': 'expr', 'nodes': [
'expr': [
{ 'operand': [{ 'string': '"str"' }] },
{ 'infix-operator': [{ 'period': '.' }] },
{
'name': 'operand', 'nodes': [
{ 'name': 'open-paren', 'value': '(' },
{
'name': 'expr',
'nodes': [
{ 'name': 'operand', 'nodes': [{ 'name': 'identifier', 'value': 'foo' }] },
{
'name': 'postfix-op', 'nodes': [
{
'name': 'call-op', 'nodes': [
{ 'name': 'open-paren', 'value': '(' },
{
'name': 'args', 'nodes': [
{
'name': 'expr',
'nodes': [{
'name': 'operand',
'nodes': [{ 'name': 'number', 'value': '12' }]
}]
}
]
}, { 'name': 'close-paren', 'value': ')' }]
}]
},
{ 'name': 'infix-operator', 'nodes': [{ 'name': 'slash', 'value': '/' }] },
{ 'name': 'operand', 'nodes': [{ 'name': 'number', 'value': '4' }] }
'expr': [{ 'operand': [{ 'identifier': 'ok' }] }, {
'postfix-op': [{
'call-op': [
{ 'open-paren': '(' },
{ 'args': [{ 'expr': [{ 'operand': [{ 'number': '4' }] }] }] },
{ 'close-paren': ')' }
]
},
{ 'name': 'close-paren', 'value': ')' }]
},
{ 'name': 'infix-operator', 'nodes': [{ 'name': 'asterisk', 'value': '*' }] },
{ 'name': 'operand', 'nodes': [{ 'name': 'string', 'value': '"str"' }] }
}]
}]
}
]
})
})

it('parse function-expr', () => {
const code = `(): Unit {}`
const rule = parseToken(code, 'expr')
it('parse expr continuous', () => {
const rule = parseToken('1 + 2 + 3', 'expr')
expect(compactToken(rule!)).toEqual({
'expr': [
{ 'operand': [{ 'number': '1' }] },
{ 'infix-operator': [{ 'plus': '+' }] },
{
'expr': [
{ 'operand': [{ 'number': '2' }] },
{ 'infix-operator': [{ 'plus': '+' }] },
{ 'expr': [{ 'operand': [{ 'number': '3' }] }] }
]
}
]
})
})

it('parse expr parens', () => {
const rule = parseToken('(foo(12) / 4)', 'expr')
expect(compactToken(rule!)).toEqual({
'name': 'expr', 'nodes': [{
'name': 'operand', 'nodes': [{
'name': 'function-expr',
'nodes': [
{ 'name': 'open-paren', 'value': '(' },
{ 'name': 'close-paren', 'value': ')' },
{ 'name': 'colon', 'value': ':' },
'expr': [{
'operand': [{ 'open-paren': '(' }, {
'expr': [
{ 'operand': [{ 'identifier': 'foo' }] },
{
'name': 'type',
'nodes': [
{ 'name': 'identifier', 'value': 'Unit' }
]
'postfix-op': [{
'call-op': [
{ 'open-paren': '(' },
{ 'args': [{ 'expr': [{ 'operand': [{ 'number': '12' }] }] }] },
{ 'close-paren': ')' }
]
}]
},
{
'name': 'block',
'nodes': [
{ 'name': 'open-brace', 'value': '{' },
{ 'name': 'close-brace', 'value': '}' }
]
}
],
}]
{ 'infix-operator': [{ 'slash': '/' }] },
{ 'expr': [{ 'operand': [{ 'number': '4' }] }] }
]
}, { 'close-paren': ')' }]
}]
})
})

it('parse expr complex', () => {
const rule = parseToken('(foo(12) / 4) * "str".ok()', 'expr')
const parenExpr = {
'operand': [
{ 'open-paren': '(' },
{
'expr': [
{ 'operand': [{ 'identifier': 'foo' }] },
{
'postfix-op': [{
'call-op': [
{ 'open-paren': '(' },
{ 'args': [{ 'expr': [{ 'operand': [{ 'number': '12' }] }] }] },
{ 'close-paren': ')' }
]
}]
},
{ 'infix-operator': [{ 'slash': '/' }] },
{ 'expr': [{ 'operand': [{ 'number': '4' }] }] }
]
},
{ 'close-paren': ')' }
]
}
const methodCallExpr = {
'expr': [
{ 'operand': [{ 'string': '"str"' }] },
{ 'infix-operator': [{ 'period': '.' }] },
{
'expr': [
{ 'operand': [{ 'identifier': 'ok' }] },
{ 'postfix-op': [{ 'call-op': [{ 'open-paren': '(' }, { 'close-paren': ')' }] }] }
]
}
]
}
expect(compactToken(rule!)).toEqual({
'expr': [parenExpr, { 'infix-operator': [{ 'asterisk': '*' }] }, methodCallExpr]
})
})

Expand Down
4 changes: 2 additions & 2 deletions src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ export const parserTokensOnly = (token: ParserToken): ParserToken => {

export const compactToken = (token: Token): any => {
if ('nodes' in token) {
return { name: token.name, nodes: token.nodes.map(n => compactToken(n)) }
return { [token.name]: token.nodes.map(n => compactToken(n)) }
} else {
return { name: token.name, value: token.value }
return { [token.name]: token.value }
}
}

0 comments on commit 0e1d8a8

Please sign in to comment.