Skip to content

Commit

Permalink
✨ feat(binary-expresison): implement parse complex binary logic
Browse files Browse the repository at this point in the history
  • Loading branch information
h-vien committed May 23, 2024
1 parent d38ab88 commit 1f34889
Show file tree
Hide file tree
Showing 16 changed files with 224 additions and 155 deletions.
9 changes: 7 additions & 2 deletions package/src/__test__/test.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { transpiler } from '@parser'
import { Expression } from '@parser/nodes/expressions/index'
import { Program } from '@parser/program'
import { parserNode } from '@parser/test'

Expand Down Expand Up @@ -37,8 +39,11 @@ describe('Test every thing', () => {
in ra (a)
a++
}`
const test = ` test = 2 + i -1`
const test = `khai báo a = {
a: 1
}
in ra(a.a)
`
const result = parserNode.parse(test, Program)
console.log(JSON.stringify(result, null, 2))
})
})
5 changes: 4 additions & 1 deletion package/src/constants/keyword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,8 @@ export enum Keyword {
INSTANCEOF = 'Instanceof',
WITH = 'With',
DEBUGGER = 'Debugger',
IDENTIFIER = 'Identifier'
IDENTIFIER = 'Identifier',
RELATIONAL_OPERATOR = 'RelationalOperator',
ADDITIVE_OPERATOR = 'AdditiveOperator',
MULTIPLICATIVE_OPERATOR = 'MultiplicativeOperator'
}
9 changes: 8 additions & 1 deletion package/src/constants/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ export const Specs: Array<Spec> = [
// Skip multi-line comments:
[/^\/\*[\S\s]*?\*\//, null],

[/^\+\+/, '++'], // PlusPlus

// --------------------------------------
// Math operators: +, -, *, /
[/^[+\-]/, Keyword.ADDITIVE_OPERATOR],
[/^[*\/\%]/, Keyword.MULTIPLICATIVE_OPERATOR],
// Relational operators: >, >=, <, <=
[/^(<=|>=|<|>|==)/, Keyword.RELATIONAL_OPERATOR],
// --------------------------------------
// Symbols and delimiters:
[/^\[/, '['], // OpenBracket
Expand All @@ -36,7 +44,6 @@ export const Specs: Array<Spec> = [
[/^:/, ':'], // Colon
[/^\.{3}/, '...'], // Ellipsis
[/^\./, '.'], // Dot
[/^\+\+/, '++'], // PlusPlus
[/^\+/, '+'], // Plus
[/^--/, '--'], // MinusMinus
[/^-/, '-'], // Minus
Expand Down
26 changes: 11 additions & 15 deletions package/src/nodes/expressions/__test__/assignment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,28 @@ import { AssignmentExpression } from '../assignment'
describe('expression-assignment.test', () => {
it('should parse the syntax normally', () => {
const result = parserNode.parse('a = 12;', AssignmentExpression)
expect(toPlainObject(result)).toStrictEqual({
expect(toPlainObject(result)).toEqual({
type: 'AssignmentExpression',
left: {
type: 'Identifier',
name: 'a'
},
operator: '=',
right: {
type: 'BinaryExpression',
left: {
type: 'NumericLiteral',
start: 4,
end: 6,
value: 12,
extra: {
rawValue: 12,
raw: '12'
}
},
right: {}
type: 'NumericLiteral',
start: 4,
end: 6,
value: 12,
extra: {
rawValue: 12,
raw: '12'
}
}
})
})
it('Should parse the syntax with a complex expression', () => {
const result = parserNode.parse('a = 12 + 2;', AssignmentExpression)
expect(toPlainObject(result)).toStrictEqual({
expect(toPlainObject(result)).toEqual({
type: 'AssignmentExpression',
left: {
type: 'Identifier',
Expand All @@ -39,6 +35,7 @@ describe('expression-assignment.test', () => {
operator: '=',
right: {
type: 'BinaryExpression',
operator: '+',
left: {
type: 'NumericLiteral',
start: 4,
Expand All @@ -49,7 +46,6 @@ describe('expression-assignment.test', () => {
raw: '12'
}
},
operator: '+',
right: {
type: 'NumericLiteral',
start: 9,
Expand Down
73 changes: 62 additions & 11 deletions package/src/nodes/expressions/__test__/binary.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,77 @@
import { parserNode } from '@parser/test'
import toPlainObject from '@parser/utils/toPlainObject'
import { BinaryExpression } from '../binary'
import { Expression } from '../index'
import { BinaryExpression } from '../binary/index'

describe('expression-binary.test', () => {
it('should parse the syntax normally', () => {
const result = parserNode.parse('xin chào === hello', Expression)

expect(toPlainObject(result)).toStrictEqual({
type: 'BinaryExpression',
operator: '===',
const res = parserNode.parse('a = 1 + 2 ', Expression)
expect(toPlainObject(res)).toEqual({
type: 'AssignmentExpression',
left: {
type: 'Identifier',
name: 'xin_ch_224o'
name: 'a'
},
operator: '=',
right: {
type: 'Identifier',
name: 'hello'
type: 'BinaryExpression',
operator: '+',
left: {
type: 'NumericLiteral',
start: 4,
end: 5,
value: 1,
extra: {
rawValue: 1,
raw: '1'
}
},
right: {
type: 'NumericLiteral',
start: 8,
end: 9,
value: 2,
extra: {
rawValue: 2,
raw: '2'
}
}
}
} as BinaryExpression)
})
})
it('should parse the syntax normally', () => {
const res = parserNode.parse('a = 1 + 2 ', Expression)
const res = parserNode.parse('a - 1 * 2 ', BinaryExpression)
expect(toPlainObject(res)).toEqual({
type: 'BinaryExpression',
left: {
type: 'Identifier',
name: 'a'
},
operator: '-',
right: {
type: 'BinaryExpression',
operator: '*',
left: {
type: 'NumericLiteral',
start: 4,
end: 5,
value: 1,
extra: {
rawValue: 1,
raw: '1'
}
},
right: {
type: 'NumericLiteral',
start: 8,
end: 9,
value: 2,
extra: {
rawValue: 2,
raw: '2'
}
}
}
})
})
})
24 changes: 0 additions & 24 deletions package/src/nodes/expressions/__test__/unary.test.ts

This file was deleted.

8 changes: 4 additions & 4 deletions package/src/nodes/expressions/assignment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Keyword } from '@parser/constants/keyword'
import { Identifier } from '../identifier/index'
import { Expression } from './index'
import { BinaryExpression } from './binary/index'
import { BinaryExpressionBuilder } from './binary/builder'

export class AssignmentExpression {
type = 'AssignmentExpression'
Expand All @@ -16,11 +17,10 @@ export class AssignmentExpression {
constructor(parser: Parser, identifier?: Identifier | Expression) {
this.left =
identifier ?? (parser.nextToken?.type === Keyword.IDENTIFIER ? new Identifier(parser) : new Expression(parser))

while (parser.nextToken?.type === '=') {
this.operator = String(parser.validate('=').value)
this.right = new BinaryExpression(parser)
return
this.operator = String(parser.validate(parser.nextToken?.type as any).value)
const binaryBuilder = new BinaryExpressionBuilder(parser, identifier as Identifier)
this.right = binaryBuilder.RelationalExpression()
}
}
}
48 changes: 35 additions & 13 deletions package/src/nodes/expressions/binary/builder.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Identifier } from '@parser/nodes/identifier/index'
import { Expression } from '../index'
import { Keyword } from '@parser/constants/keyword'
import { Parser } from '@parser/parser'
import { Token } from '@parser/types/token'
import { Operator } from '@parser/types/operator'
import { UnaryExpression } from '../unary'
import { Literal } from '@parser/nodes/literal/index'
import { Expression } from '../index'
import { Identifier } from '@parser/nodes/identifier/index'

export class BinaryExpressionBuilder {
parser: Parser
constructor(_parser: Parser) {
identifier?: Identifier
constructor(_parser: Parser, _identifier?: Identifier) {
this.parser = _parser
this.identifier = _identifier
}
BuilderExpression(builderName: string, operatorToken: Operator) {
BuilderExpression(builderName: string, operatorToken: Token['type']) {
let left = this[builderName]?.()

while (this.parser.nextToken?.type === operatorToken) {
const operator = this.parser.validate(operatorToken).value
const right = this[builderName]()
Expand All @@ -22,17 +25,36 @@ export class BinaryExpressionBuilder {
right
}
}

return left
}

AdditiveExpression() {
console.log('vao dau')
return {
type: 'BinaryExpression',
operator: '+',
left: new Identifier(this.parser),
right: new Expression(this.parser)
const res = this.BuilderExpression('MultiplicativeExpression', Keyword.ADDITIVE_OPERATOR)
return res
}
MultiplicativeExpression() {
const res = this.BuilderExpression('PrimaryExpression', Keyword.MULTIPLICATIVE_OPERATOR)
return res
}
RelationalExpression() {
const res = this.BuilderExpression('AdditiveExpression', Keyword.RELATIONAL_OPERATOR)
return res
}
PrimaryExpression() {
switch (this.parser.nextToken?.type) {
case '(':
return this.ParenthesizedExpression()
case Keyword.IDENTIFIER:
return new Identifier(this.parser)
default:
return new Literal(this.parser)
}
}

ParenthesizedExpression() {
this.parser.validate('(')
const expression = new Expression(this.parser)
this.parser.validate(')')
return expression
}
}
43 changes: 13 additions & 30 deletions package/src/nodes/expressions/binary/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,29 @@ import { Identifier } from '@parser/nodes/identifier/index'
import { Parser } from '@parser/parser'
import { Expression } from '../index'
import { BinaryExpressionBuilder } from './builder'
import { Operator } from '@parser/types/operator'
import { CLIENT_RENEG_LIMIT } from 'tls'

export class BinaryExpression {
type = 'BinaryExpression'

left: Identifier | Expression

operator: string | undefined
operator?: string

right: Identifier | Expression
right?: Identifier | Expression

constructor(parser: Parser, identifier?: Identifier) {
const binaryBuilder = new BinaryExpressionBuilder(parser)
this.left =
identifier ??
(parser.nextToken?.type === Keyword.IDENTIFIER ? new Identifier(parser) : binaryBuilder.AdditiveExpression())
switch (parser.nextToken?.type) {
case '+':
case '-':
case '*':
case '/':
case '%':
case '**':
case '^':
case '>':
case '>>':
case '>>>':
case '<':
case '<<':
case '<<<':
case '>=':
case '<=':
case '==':
case '===': {
this.operator = String(parser.validate(parser.nextToken?.type).value)
break
}
}
identifier ?? (parser.nextToken?.type === Keyword.IDENTIFIER ? new Identifier(parser) : new Expression(parser))

while (
[Keyword.RELATIONAL_OPERATOR, Keyword.ADDITIVE_OPERATOR, Keyword.MULTIPLICATIVE_OPERATOR].includes(
parser.nextToken?.type as Keyword
)
) {
this.operator = String(parser.validate(parser.nextToken?.type as any).value)
const binaryBuilder = new BinaryExpressionBuilder(parser, identifier)

this.right = new Expression(parser)
this.right = binaryBuilder.RelationalExpression()
}
}
}
5 changes: 4 additions & 1 deletion package/src/nodes/expressions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ export class Expression {
case '>=':
case '<=':
case '==':
case '===': {
case '===':
case Keyword.ADDITIVE_OPERATOR:
case Keyword.MULTIPLICATIVE_OPERATOR:
case Keyword.RELATIONAL_OPERATOR: {
Object.assign(this, new BinaryExpression(parser, identifier))
break
}
Expand Down
Loading

0 comments on commit 1f34889

Please sign in to comment.