Skip to content

Commit

Permalink
Use statement
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Jun 17, 2023
1 parent 0a4eda7 commit 886c949
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 19 deletions.
7 changes: 3 additions & 4 deletions data/features.no
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// TODO: imports
// use std::Display
// use std::io::{println}
// use std::Option::*
use std::Display
use std::io::{println}
use std::Option::*

// type
type Unit
Expand Down
10 changes: 9 additions & 1 deletion nois.bnf
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
module ::= statement*
;
statement ::= var-def | fn-def | kind-def | impl-def | type-def | return-stmt | expr
statement ::= use-stmt | var-def | fn-def | kind-def | impl-def | type-def | return-stmt | expr
;
use-stmt ::= USE-KEYWORD use-expr
;
use-expr ::= (NAME COLON COLON)* (use-list | wildcard | NAME)
;
wildcard ::= ASTERISK
;
use-list ::= O-BRACE (use-expr (COMMA use-expr)*)? COMMA? C-BRACE
;
var-def ::= LET-KEYWORD pattern type-annot? EQUALS expr
;
Expand Down
6 changes: 4 additions & 2 deletions src/ast/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { buildStatement, Statement } from './statement'
import { buildPattern, Pattern } from './match'
import { ParseNode, ParseTree, treeKinds } from '../parser/parser'
import { NodeKind, ParseNode, ParseTree, treeKinds } from '../parser/parser'
import { lexerDynamicKinds } from '../lexer/lexer'
import { buildIdentifier, buildName, Identifier, Name } from './operand'
import { buildExpr, Expr } from './expr'
Expand All @@ -12,6 +12,8 @@ export interface AstNode<T extends AstNodeKind> {

export type AstNodeKind
= 'module'
| 'use-expr'
| 'wildcard'
| 'var-def'
| 'fn-def'
| 'kind-def'
Expand Down Expand Up @@ -67,7 +69,7 @@ export type AstNodeKind
| 'or-op'
| 'assign-op'

export const astNodes = [...lexerDynamicKinds, ...treeKinds]
export const astNodes: NodeKind[] = [...lexerDynamicKinds, ...treeKinds]

export const filterNonAstNodes = (node: ParseNode): ParseNode[] =>
(<ParseTree>node).nodes.filter(n => astNodes.includes(n.kind))
Expand Down
27 changes: 25 additions & 2 deletions src/ast/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ import { buildTypeDef, TypeDef } from './type-def'
import { buildExpr, Expr } from './expr'
import { buildPattern, Pattern } from './match'
import { ParseNode, ParseTree } from '../parser/parser'
import { Identifier } from './operand'
import { buildName, Identifier, Name } from './operand'

export type Statement = VarDef | FnDef | KindDef | ImplDef | TypeDef | ReturnStmt | Expr
export type Statement = UseExpr | VarDef | FnDef | KindDef | ImplDef | TypeDef | ReturnStmt | Expr

export const buildStatement = (node: ParseNode): Statement => {
const n = (<ParseTree>node).nodes[0]
switch (n.kind) {
case 'use-stmt':
return buildUseExpr(n)
case 'var-def':
return buildVarDef(n)
case 'fn-def':
Expand All @@ -28,6 +30,27 @@ export const buildStatement = (node: ParseNode): Statement => {
throw Error(`expected statement, got ${node.kind}`)
}

export interface UseExpr extends AstNode<'use-expr'> {
scope: Name[]
expr: UseExpr[] | Name | Wildcard
}

export const buildUseExpr = (node: ParseNode): UseExpr => {
const nodes = filterNonAstNodes(node.kind === 'use-stmt' ? filterNonAstNodes(node)[0] : node)
const names = nodes.filter(n => n.kind === 'name').map(buildName)
if (nodes.at(-1)!.kind === 'wildcard') {
const scope = names
return { type: 'use-expr', parseNode: node, scope, expr: { type: 'wildcard', parseNode: nodes.at(-1)! } }
}
if (nodes.at(-1)!.kind === 'use-list') {
const scope = names
return { type: 'use-expr', parseNode: node, scope, expr: filterNonAstNodes(nodes.at(-1)!).map(buildUseExpr) }
}
return { type: 'use-expr', parseNode: node, scope: names.slice(0, -1), expr: names.at(-1)! }
}

export interface Wildcard extends AstNode<'wildcard'> {}

export interface VarDef extends AstNode<'var-def'> {
pattern: Pattern
varType?: Type
Expand Down
25 changes: 19 additions & 6 deletions src/lexer/lexer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { LocationRange } from '../location'
import { NodeKind } from '../parser/parser'

export const lexerOperatorKinds = ['plus', 'minus', 'asterisk', 'slash', 'caret', 'percent', 'ampersand', 'pipe', 'excl', 'period']
export const lexerOperatorKinds = <const>[
'plus',
'minus',
'asterisk',
'slash',
'caret',
'percent',
'ampersand',
'pipe',
'excl',
'period'
]

export const lexerPunctuationKinds = [
export const lexerPunctuationKinds = <const>[
'o-paren',
'c-paren',
'o-bracket',
Expand All @@ -18,7 +29,8 @@ export const lexerPunctuationKinds = [
'underscore',
'arrow']

export const lexerKeywordKinds = [
export const lexerKeywordKinds = <const>[
'use-keyword',
'type-keyword',
'kind-keyword',
'impl-keyword',
Expand All @@ -33,11 +45,11 @@ export const lexerKeywordKinds = [
'match-keyword'
]

export const lexerDynamicKinds = ['name', 'string', 'char', 'int', 'float']
export const lexerDynamicKinds = <const>['name', 'string', 'char', 'int', 'float']

const lexerParseIndependentKinds = ['newline', 'comment']
const lexerParseIndependentKinds = <const>['newline', 'comment']

const lexerSpecialKinds = ['unknown', 'unterminated-string', 'unterminated-char', 'eof']
const lexerSpecialKinds = <const>['unknown', 'unterminated-string', 'unterminated-char', 'eof']

export const lexerTokenKinds = <const>[
...lexerKeywordKinds,
Expand All @@ -59,6 +71,7 @@ export interface ParseToken {
}

export const constTokenKindMap: Map<TokenKind, string> = new Map([
['use-keyword', 'use'],
['type-keyword', 'type'],
['kind-keyword', 'kind'],
['if-keyword', 'if'],
Expand Down
1 change: 1 addition & 0 deletions src/parser/fns/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const infixOpFirstTokens: TokenKind[] = ['ampersand', 'asterisk', 'c-angl
export const exprFirstTokens: TokenKind[] = ['char', 'name', 'if-keyword', 'while-keyword', 'for-keyword',
'match-keyword', 'int', 'float', 'o-bracket', 'o-paren', 'string', ...prefixOpFirstTokens]
export const paramFirstTokens: TokenKind[] = ['name']
export const useExprFirstTokens: TokenKind[] = ['name', 'asterisk', 'o-brace']

/**
* module ::= statement*
Expand Down
66 changes: 62 additions & 4 deletions src/parser/fns/statement.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Parser } from '../parser'
import { parseTypeDef } from './type-def'
import { exprFirstTokens, parseParams, parseTypeAnnot } from './index'
import { exprFirstTokens, parseParams, parseTypeAnnot, useExprFirstTokens } from './index'
import { parseExpr, parseTypeExpr } from './expr'
import { parsePattern } from './match'

/**
* statement ::= var-def | fn-def | kind-def | impl-def | type-def | return-stmt | expr
* statement ::= use-stmt | var-def | fn-def | kind-def | impl-def | type-def | return-stmt | expr
*/
export const parseStatement = (parser: Parser): void => {
const mark = parser.open()

if (parser.at('let-keyword')) {
if (parser.at('use-keyword')) {
parseUseStmt(parser)
} else if (parser.at('let-keyword')) {
parseVarDef(parser)
} else if (parser.at('fn-keyword')) {
parseFnDef(parser)
Expand All @@ -32,7 +34,54 @@ export const parseStatement = (parser: Parser): void => {
}

/**
* var-def ::= LET-KEYWORD pattern type-annot? EQUALS expr
* use-stmt ::= USE-KEYWORD use-expr
*/
export const parseUseStmt = (parser: Parser): void => {
const mark = parser.open()
parser.expect('use-keyword')
parseUseExpr(parser)
parser.close(mark, 'use-stmt')
}

/**
* use-expr ::= (NAME COLON COLON)* (use-list | NAME | ASTERISK)
*/
export const parseUseExpr = (parser: Parser): void => {
const mark = parser.open()
while (parser.at('name') && parser.nth(1) === 'colon' && parser.nth(2) === 'colon' && !parser.eof()) {
parser.expect('name')
parser.expect('colon')
parser.expect('colon')
}
if (parser.at('o-brace')) {
parseUseList(parser)
} else if (parser.consume('name')) {
} else if (parser.at('asterisk')) {
parseWildcard(parser)
} else {
parser.advanceWithError('expected use-expr')
}
parser.close(mark, 'use-expr')
}

/**
* use-list ::= O-BRACE (use-expr (COMMA use-expr)*)? COMMA? C-BRACE
*/
export const parseUseList = (parser: Parser): void => {
const mark = parser.open()
parser.expect('o-brace')
while (parser.atAny(useExprFirstTokens) && !parser.eof()) {
parseUseExpr(parser)
if (!parser.at('c-brace')) {
parser.expect('comma')
}
}
parser.expect('c-brace')
parser.close(mark, 'use-list')
}

/**
* use-list ::= O-BRACE (use-expr (COMMA use-expr)*)? COMMA? C-BRACE
*/
export const parseVarDef = (parser: Parser): void => {
const mark = parser.open()
Expand All @@ -46,6 +95,15 @@ export const parseVarDef = (parser: Parser): void => {
parser.close(mark, 'var-def')
}

/**
* wildcard ::= ASTERISK
*/
export const parseWildcard = (parser: Parser): void => {
const mark = parser.open()
parser.expect('asterisk')
parser.close(mark, 'wildcard')
}

/**
* fn-def ::= FN-KEYWORD type-expr O-PAREN params? C-PAREN type-annot? block?
*/
Expand Down
4 changes: 4 additions & 0 deletions src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export const treeKinds = <const>[
'error',
'module',
'statement',
'use-stmt',
'use-expr',
'use-list',
'var-def',
'fn-def',
'kind-def',
Expand Down Expand Up @@ -70,6 +73,7 @@ export const treeKinds = <const>[
'con-pattern-params',
'field-pattern',
'hole',
'wildcard',
]
export type TreeKind = typeof treeKinds[number]

Expand Down

0 comments on commit 886c949

Please sign in to comment.