Skip to content

Commit

Permalink
Overhaul start
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanjermakov committed Jul 17, 2024
1 parent b52fea0 commit f6ea30d
Show file tree
Hide file tree
Showing 40 changed files with 719 additions and 773 deletions.
78 changes: 78 additions & 0 deletions data/nois3.no
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// expressive type system: Haskell, Rust
// algebraic data types
// type aliases
// traits and impl specialization
// specialization type hint? e.g. foo.<Into<Bar>>into()
// polymorphic parameters only via trait bounds on generics (no params with trait type)
// self bounds on traits
// separate operators for Int/Float/String (e.g. +, +., ++) for better type inference
//
// Compiler phases:
// - Create AST
// - Lexing
// - Parsing
// - Name resolution
// - Module resolution (find names accessible outside of the module)
// - Name resolution (resolve all names to their definition)
// - Semantic check
// - No stupid things like missing method impls, illogical match statements
// - Type check
// - Constraint gathering (how factors constraint node's type: type annotations, usage as argument, return type)
// - Constraint unification (trying to combine constraints into a most broad type)
// - Type semantics (proper impl definition, match refutablility, call integrity)
// - Impl resolution (static dispatch references, dynamic dispatch upcasts)
// - Codegen

type Option<T> {
Some(value T)
None()
}

type User(name Name, age Int)

type Name = String

trait Eq {
fn eq(self, other Self) Bool
}

trait Ord<Self: Eq> {
fn cmp(self, other Self) Ordering

fn lt(self, other Self) Bool {
self.cmp(other) == Less
}
}

trait Show {
fn show(self) String
}

impl Show for Option<User> {
fn show(self) String {
"Maybe user!!!"
}
}

impl <T: Eq + Ord> Show for Option<T> {
fn show(self) String {
match self {
Some(value) { value.show() }
None() { "None" }
}
}
}

fn main() {

let u = User("Jack", 13)
let u = User(name = "Jack", age = 13)

let m = Some(5)
let value = 5
match m) {
Some(value) { m.value },
None() { ... }
}
}

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@types/jasmine": "~4.3.5",
"@types/node": "~18.16.20",
"bun": "~1.0.23",
"typescript": "~5.3.3"
}
"typescript": "~5.5.3"
},
"packageManager": "[email protected]"
}
12 changes: 7 additions & 5 deletions src/ast/expr.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { ParseNode, filterNonAstNodes } from '../parser'
import { Context, addError } from '../scope'
import { Typed, Virtual } from '../semantic'
import { invalidOperatorChainError } from '../semantic/error'
import { assert } from '../util/todo'
import { AstNode } from './index'
import { BaseAstNode } from './index'
import { BinaryOp, PostfixOp, associativityMap, buildBinaryOp, buildPostfixOp, precedenceMap } from './op'
import { Operand, buildOperand } from './operand'

export type Expr = OperandExpr | UnaryExpr | BinaryExpr

export interface OperandExpr extends AstNode<'operand-expr'>, Partial<Typed>, Partial<Virtual> {
export type OperandExpr = BaseAstNode & {
kind: 'operand-expr'
operand: Operand
}

Expand All @@ -21,12 +21,14 @@ export const buildOperandExpr = (node: ParseNode, ctx: Context): OperandExpr =>
}
}

export interface UnaryExpr extends AstNode<'unary-expr'>, Partial<Typed>, Partial<Virtual> {
export type UnaryExpr = BaseAstNode & {
kind: 'unary-expr'
operand: Operand
op: PostfixOp
}

export interface BinaryExpr extends AstNode<'binary-expr'>, Partial<Typed>, Partial<Virtual> {
export type BinaryExpr = BaseAstNode & {
kind: 'binary-expr'
binaryOp: BinaryOp
lOperand: Operand
rOperand: Operand
Expand Down
159 changes: 136 additions & 23 deletions src/ast/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,130 @@
import { ParseNode, filterNonAstNodes } from '../parser'
import { Context, Scope } from '../scope'
import { InstanceRelation } from '../scope/trait'
import { Context, DefinitionMap } from '../scope'
import { VirtualIdentifier, VirtualIdentifierMatch } from '../scope/vid'
import { Typed } from '../semantic'
import { VirtualUseExpr } from '../semantic/use-expr'
import { Source } from '../source'
import { Expr, buildExpr } from './expr'
import { Pattern, buildPattern } from './match'
import { Name, buildName } from './operand'
import { Block, UseExpr, buildStatement, buildUseExpr } from './statement'
import { Type, buildType } from './type'

export interface AstNode<T extends AstNodeKind> {
kind: T
import { BinaryExpr, Expr, OperandExpr, UnaryExpr, buildExpr } from './expr'
import { ConPattern, FieldPattern, Hole, ListPattern, MatchClause, MatchExpr, Pattern, buildPattern } from './match'
import {
AddOp,
AndOp,
AssignOp,
AwaitOp,
BindOp,
CallOp,
DivOp,
EqOp,
ExpOp,
FieldAccessOp,
GeOp,
GtOp,
LeOp,
LtOp,
MethodCallOp,
ModOp,
MultOp,
NeOp,
OrOp,
SubOp,
UnwrapOp
} from './op'
import {
BoolLiteral,
CharLiteral,
ClosureExpr,
FloatLiteral,
ForExpr,
Identifier,
IfExpr,
IfLetExpr,
IntLiteral,
ListExpr,
Name,
StringInterpolated,
StringLiteral,
WhileExpr,
buildName
} from './operand'
import {
Block,
BreakStmt,
FnDef,
ImplDef,
ReturnStmt,
TraitDef,
UseExpr,
VarDef,
buildStatement,
buildUseExpr
} from './statement'
import { FnType, Generic, Type, TypeBounds, buildType } from './type'
import { FieldDef, TypeDef, Variant } from './type-def'

export type AstNode =
| Module
| UseExpr
| Variant
| ReturnStmt
| BreakStmt
| Arg
| Block
| Param
| TypeBounds
| FnType
| Generic
| IfExpr
| MatchClause
| Pattern
| ConPattern
| ListPattern
| FieldPattern
| Hole
| Identifier
| Name
| StringInterpolated
| OperandExpr
| UnaryExpr
| BinaryExpr
| ClosureExpr
| ListExpr
| IfLetExpr
| WhileExpr
| ForExpr
| MatchExpr
| VarDef
| FnDef
| TraitDef
| ImplDef
| TypeDef
| FieldDef
| StringLiteral
| CharLiteral
| IntLiteral
| FloatLiteral
| BoolLiteral
| AddOp
| SubOp
| MultOp
| DivOp
| ExpOp
| ModOp
| EqOp
| NeOp
| GeOp
| LeOp
| GtOp
| LtOp
| AndOp
| OrOp
| AssignOp
| MethodCallOp
| FieldAccessOp
| CallOp
| UnwrapOp
| BindOp
| AwaitOp

export type BaseAstNode = {
parseNode: ParseNode
}

Expand Down Expand Up @@ -65,7 +177,6 @@ export const astKinds = <const>[
'variant',
'return-stmt',
'break-stmt',
'call',
'arg',
'block',
'param',
Expand All @@ -91,7 +202,7 @@ export const astKinds = <const>[

export type AstNodeKind = (typeof astKinds)[number]

export const compactAstNode = (node: AstNode<any>): any => {
export const compactAstNode = (node: AstNode): any => {
if (typeof node !== 'object') return node
return Object.fromEntries(
Object.entries(node)
Expand All @@ -108,13 +219,14 @@ export const compactAstNode = (node: AstNode<any>): any => {
)
}

export interface Module extends AstNode<'module'> {
export type Module = BaseAstNode & {
kind: 'module'
source: Source
identifier: VirtualIdentifier
mod: boolean
block: Block

scopeStack: Scope[]
scopeStack: DefinitionMap[]
useExprs: UseExpr[]

/**
Expand All @@ -126,17 +238,15 @@ export interface Module extends AstNode<'module'> {
*/
reExports?: VirtualUseExpr[]
/**
* Persistent top level scope.
* Different from scopeStack[0] because it is always available
* If module is accessed during its check, use scopeStack.at(0) instead
* Persistent top level scope
*/
topScope?: Scope
topScope: DefinitionMap
compiled: boolean
/**
* List of resolved imports used by this module
*/
imports: VirtualIdentifierMatch[]
relImports: InstanceRelation[]
useScope: DefinitionMap
}

export const buildModuleAst = (
Expand All @@ -160,13 +270,15 @@ export const buildModuleAst = (
block,
scopeStack: [],
useExprs,
topScope: new Map(),
compiled,
imports: [],
relImports: []
useScope: new Map()
}
}

export interface Param extends AstNode<'param'>, Partial<Typed> {
export type Param = BaseAstNode & {
kind: 'param'
pattern: Pattern
paramType?: Type
}
Expand All @@ -178,7 +290,8 @@ export const buildParam = (node: ParseNode, ctx: Context): Param => {
return { kind: 'param', parseNode: node, pattern, paramType: typeNode ? buildType(typeNode, ctx) : undefined }
}

export interface Arg extends AstNode<'arg'> {
export type Arg = BaseAstNode & {
kind: 'arg'
name?: Name
expr: Expr
}
Expand Down
Loading

0 comments on commit f6ea30d

Please sign in to comment.