Skip to content

Commit

Permalink
Generic bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Jun 16, 2023
1 parent 7332b0f commit 0e040e6
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 18 deletions.
8 changes: 3 additions & 5 deletions data/features.no
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ impl Display for Vec2 {
// function
fn add(a: Int, b: Int): Int { a + b }

// function generics
fn pushIf<T>(flag: Bool, l: List<T>, item: T): Unit {
if (flag) {
l.push(item)
}
// function generics and generic bounds
fn foo<T: Add + Div>(a: T, b: T): T {
a.add(b).div(b)
}

// define variable
Expand Down
6 changes: 5 additions & 1 deletion nois.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ type-annot ::= COLON type-expr
;
type-expr ::= IDENTIFIER type-params?
;
type-params ::= O-ANGLE (type-expr (COMMA type-expr)* COMMA?)? C-ANGLE
type-params ::= O-ANGLE (type-param (COMMA type-param)* COMMA?)? C-ANGLE
;
type-param ::= type-expr | IDENTIFIER COLON type-bounds
;
type-bounds ::= type-expr (PLUS type-expr)*
;
if-expr ::= IF-KEYWORD expr block (ELSE-KEYWORD block)?
;
Expand Down
27 changes: 24 additions & 3 deletions src/ast/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type AstNodeKind
| 'list-expr'
| 'param'
| 'type'
| 'type-param'
| 'if-expr'
| 'while-expr'
| 'for-expr'
Expand Down Expand Up @@ -84,11 +85,19 @@ export const buildModule = (node: ParseNode): Module => {

export interface Type extends AstNode<'type'> {
identifier: Identifier
typeParams: Type[]
typeParams: TypeParam[]
}

export interface TypeParam extends AstNode<'type-param'> {
identifier: Identifier
bounds: Type[]
}

export const buildType = (node: ParseNode): Type => {
const nodes = filterNonAstNodes(node)
if (node.kind === 'type-annot') {
return buildType(nodes[0])
}
const nameNode = nodes[0]
const paramsNode = nodes.at(1)
return {
Expand All @@ -97,12 +106,24 @@ export const buildType = (node: ParseNode): Type => {
identifier: buildIdentifier(nameNode),
typeParams: paramsNode
? (<ParseTree>paramsNode).nodes
.filter(n => n.kind === 'type-params')
.map(n => buildType((<ParseTree>n).nodes[0]))
.filter(n => n.kind === 'type-param')
.map(buildTypeParam)
: [],
}
}

export const buildTypeParam = (node: ParseNode): TypeParam => {
const nodes = filterNonAstNodes(node)
if (nodes[0].kind === 'type-expr') {
const { identifier } = buildType(nodes[0])
return { type: 'type-param', parseNode: node, identifier, bounds: [] }
} else {
const identifier = buildIdentifier(nodes[0])
const bounds = filterNonAstNodes(nodes[1]).map(buildType)
return { type: 'type-param', parseNode: node, identifier, bounds }
}
}

export interface Param extends AstNode<'param'> {
pattern: Pattern
paramType?: Type
Expand Down
8 changes: 4 additions & 4 deletions src/ast/statement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AstNode, buildParam, buildType, filterNonAstNodes, Param, Type } from './index'
import { AstNode, buildParam, buildType, filterNonAstNodes, Param, Type, TypeParam } from './index'
import { buildTypeDef, TypeDef } from './type-def'
import { buildExpr, Expr } from './expr'
import { buildPattern, Pattern } from './match'
Expand Down Expand Up @@ -46,7 +46,7 @@ export const buildVarDef = (node: ParseNode): VarDef => {
export interface FnDef extends AstNode<'fn-def'> {
type: 'fn-def'
identifier: Identifier
typeParams: Type[]
typeParams: TypeParam[]
params: Param[]
block?: Block
returnType?: Type
Expand All @@ -64,7 +64,7 @@ export const buildFnDef = (node: ParseNode): FnDef => {

export interface KindDef extends AstNode<'kind-def'> {
identifier: Identifier
kindParams: Type[]
kindParams: TypeParam[]
block: Block
}

Expand All @@ -77,7 +77,7 @@ export const buildKindDef = (node: ParseNode): KindDef => {

export interface ImplDef extends AstNode<'impl-def'> {
identifier: Identifier
implParams: Type[]
implParams: TypeParam[]
forKind?: Type
block: Block
}
Expand Down
4 changes: 2 additions & 2 deletions src/ast/type-def.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { AstNode, buildType, filterNonAstNodes, Type } from './index'
import { AstNode, buildType, filterNonAstNodes, Type, TypeParam } from './index'
import { ParseNode } from '../parser/parser'
import { buildIdentifier, Identifier } from './operand'

export interface TypeDef extends AstNode<'type-def'> {
identifier: Identifier
typeParams: Type[]
typeParams: TypeParam[]
variants: TypeCon[]
}

Expand Down
34 changes: 31 additions & 3 deletions src/parser/fns/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,47 @@ export const parseTypeAnnot = (parser: Parser): void => {
}

/**
* type-params ::= O-ANGLE (type-expr (COMMA type-expr)* COMMA?)? C-ANGLE
* type-params ::= O-ANGLE (type-param (COMMA type-param)* COMMA?)? C-ANGLE
*/
export const parseTypeParams = (parser: Parser): void => {
const mark = parser.open()
parser.expect('o-angle')
while (!parser.at('c-angle') && !parser.eof()) {
parseTypeExpr(parser)
parseTypeParam(parser)
if (!parser.at('c-angle')) {
parser.expect('comma')
}
}
parser.expect('c-angle')
parser.close(mark, 'params')
parser.close(mark, 'type-params')
}

/**
* type-param ::= type-expr | IDENTIFIER COLON type-bounds
*/
export const parseTypeParam = (parser: Parser): void => {
const mark = parser.open()
if (parser.nth(1) === 'colon') {
parser.expect('identifier')
parser.expect('colon')
parseTypeBounds(parser)
} else {
parseTypeExpr(parser)
}
parser.close(mark, 'type-param')
}

/**
* type-bounds ::= type-expr (PLUS type-expr)*
*/
export const parseTypeBounds = (parser: Parser): void => {
const mark = parser.open()
parseTypeExpr(parser)
while (parser.at('plus') && !parser.eof()) {
parser.expect('plus')
parseTypeExpr(parser)
}
parser.close(mark, 'type-bounds')
}

export const parseTodo = (parser: Parser): void => {
Expand Down
2 changes: 2 additions & 0 deletions src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export const treeKinds = <const>[
'type-annot',
'type-expr',
'type-params',
'type-param',
'type-bounds',
'if-expr',
'while-expr',
'for-expr',
Expand Down

0 comments on commit 0e040e6

Please sign in to comment.