Skip to content

Commit

Permalink
Syntax: correct compose-op parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Nov 25, 2024
1 parent 36e94c7 commit b488915
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
2 changes: 1 addition & 1 deletion nois.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ statement ::= var-def | fn-def | trait-def | impl-def | type-def | r

postfix-op ::= compose-op | call-op | unwrap-op | bind-op | await-op
;
compose-op ::= PERIOD sub-expr
compose-op ::= PERIOD (identifier call-op | identifier | block)
;
call-op ::= O-PAREN (arg (COMMA arg)*)? COMMA? C-PAREN
;
Expand Down
3 changes: 1 addition & 2 deletions src/ast/expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ export const buildSubExpr = (node: ParseNode, ctx: Context): UnaryExpr | Operand
const operand = buildOperand(nodes[0], ctx)
const ops = nodes.slice(1).map(n => buildPostfixOp(n, ctx))
let expr: Expr = { kind: 'operand-expr', parseNode: operand.parseNode, operand }
// fold a list of ops into left-associative unary-exprs
for (const op of ops.toReversed()) {
for (const op of ops) {
expr = {
kind: 'unary-expr',
parseNode: { kind: 'expr', nodes: [expr.parseNode, op.parseNode].filter(n => !!n) },
Expand Down
29 changes: 26 additions & 3 deletions src/ast/op.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ParseNode, filterNonAstNodes } from '../parser'
import { Context } from '../scope'
import { Expr, buildSubExpr } from './expr'
import { Expr } from './expr'
import { Arg, AstNode, AstNodeKind, BaseAstNode, buildArg } from './index'
import { buildIdentifier } from './operand'
import { buildBlock } from './statement'

export type PostfixOp = ComposeOp | CallOp | UnwrapOp | BindOp | AwaitOp

Expand Down Expand Up @@ -120,8 +122,29 @@ export type ComposeOp = BaseAstNode & {
}

export const buildComposeOp = (node: ParseNode, ctx: Context): ComposeOp => {
const expr = buildSubExpr(filterNonAstNodes(node)[0], ctx)
return { kind: 'compose-op', parseNode: node, operand: expr }
const nodes = filterNonAstNodes(node)
let i = 0
let expr: Expr | undefined
if (nodes.at(i)?.kind === 'identifier') {
const id = buildIdentifier(nodes[i++], ctx)
const idExpr: Expr = { kind: 'operand-expr', parseNode: id.parseNode, operand: id }
if (nodes.at(i)?.kind === 'call-op') {
const op = buildCallOp(nodes[i++], ctx)
expr = {
kind: 'unary-expr',
parseNode: { kind: 'expr', nodes: [id, op].map(n => n.parseNode!) },
operand: idExpr,
op
}
} else {
expr = idExpr
}
}
if (nodes.at(i)?.kind === 'block') {
const block = buildBlock(nodes[i++], ctx)
expr = { kind: 'operand-expr', parseNode: block.parseNode, operand: block }
}
return { kind: 'compose-op', parseNode: node, operand: expr! }
}

export type CallOp = BaseAstNode & {
Expand Down
18 changes: 15 additions & 3 deletions src/parser/fns/op.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { nameLikeTokens } from '.'
import { Parser } from '..'
import { syntaxError } from '../../error'
import { parseExpr, parseSubExpr } from './expr'
import { parseExpr, parseIdentifier } from './expr'
import { parseBlock } from './statement'

/**
* infix-op ::= add-op | sub-op | mult-op | div-op | exp-op | mod-op | eq-op | ne-op | ge-op | le-op | gt-op
Expand Down Expand Up @@ -111,12 +112,23 @@ export const parsePostfixOp = (parser: Parser): void => {
}

/*
* compose-op ::= PERIOD sub-expr
* compose-op ::= PERIOD (identifier call-op | identifier | block)
*/
export const parseComposeOp = (parser: Parser): void => {
const mark = parser.open()
parser.expect('period')
parseSubExpr(parser)

if (parser.at('name')) {
parseIdentifier(parser)
if (parser.at('o-paren')) {
parseCallOp(parser)
}
} else if (parser.at('o-brace')) {
parseBlock(parser)
} else {
parser.advanceWithError(syntaxError(parser, 'expected infix operator'), mark)
}

parser.close(mark, 'compose-op')
}

Expand Down

0 comments on commit b488915

Please sign in to comment.