updated grammar; better LinkedList example

This commit is contained in:
Ludwig Lehnert 2025-03-05 17:02:04 +01:00
parent 3317626540
commit 63ab8998d4
11 changed files with 438 additions and 363 deletions

169
examples/LinkedList.plsm Normal file
View File

@ -0,0 +1,169 @@
module test;
import stdlib/io;
import stdlib/heap;
import stdlib/err;
trait Collection<T> {
add(item: &T) -> void;
remove(item: &T) -> void;
contains(item: &T) -> bool;
size() -> u64;
isEmpty() -> bool = self.size() > 0;
isNotEmpty() -> bool = self.size() <= 0;
each(fn: (item: &T, break: () -> void) -> void) -> void;
any(fn: (&T) -> bool) -> bool {
let mut res = false;
self.each((item, break) -> {
if fn(item) {
res = true;
break();
}
});
return res;
}
all(fn: (&T) -> bool) -> bool {
let mut res = true;
self.each((item, break) -> {
if !fn(item) {
res = false;
break();
}
});
return res;
}
// map<S>(fn: (&T) -> &S) -> Collection<S>;
// filter(fn: (&T) -> bool) -> Collection<T>;
}
trait Queue<T> : Collection<T> {
put(item: &T) -> void;
take() -> &T;
poll() -> &T?;
peek() -> &T?;
}
trait Stack<T> : Collection<T> {
push(item: &T) -> void;
pop() -> &T;
peek() -> &T?;
}
struct LinkedList<T> {
pub mut head: &T?;
pub mut tail: &LinkedList<T>?;
mut size: u64;
init() -> void {
self.head = null;
self.tail = null;
self.size = 0;
}
}
impl Collection<T> for LinkedList<T> {
add(item: &T) -> void {
if self.head == null {
self.head = item;
self.size = self.size + 1;
return;
}
if self.tail == null {
self.tail = heap.new(LinkedList);
self.tail.init();
}
self.tail.add(item);
self.size = self.size + 1;
}
remove(item: &T) -> void {
if self.head == null {
return;
}
if self.head == item {
let next = self.tail;
if next != null {
self.head = self.tail.head;
self.tail = self.tail.tail;
heap.free(next);
} else {
self.head = null;
}
self.size = self.size - 1;
return;
}
self.tail.remove(item);
self.size = self.size - 1;
}
contains(item: &T) -> bool {
if self.head == null {
return false;
}
if self.head == item {
return true;
}
return self.tail.contains(item);
}
size() -> u64 {
return self.size;
}
each(fn: (item: &T, break: () -> void) -> void) -> void {
if self.head == null {
return;
}
let mut continue = true;
fn(self.head, () -> { continue = false; });
if continue && self.tail != null {
self.tail.each(fn);
}
}
}
impl Queue<T> for LinkedList<T> {
put(item: &T) -> void = self.add(item);
take() -> &T {
if head == null {
// TODO: wait for item to be available
return null;
}
let item = self.head;
self.remove(item);
return item;
}
poll() -> &T? {
if self.head == null {
return null;
}
let item = self.head;
self.remove(item);
return item;
}
peek() -> &T? = self.head;
}

25
examples/heap.plsm Normal file
View File

@ -0,0 +1,25 @@
module memory/heap;
fun alloc(size: u64) {
// TODO
}
fun new(_struct: Struct) {
}
unsafe fun memset(addr: &u8, count: u64, value: u8) {
let i = 0;
while (i < count) {
addr[i] = value;
i += 1;
}
}
struct Array<T> {
ptr: &T;
([])(index: u64) {
}
}

View File

@ -1,70 +0,0 @@
module test;
import stdlib/io;
fun main -> {
io.println(foo() + 10);
}
trait Expr {
visit<T>(visitor: Visitor<T>): T;
}
trait ExprVisitor<T> {
visitString(string: String): T;
}
trait List<T : any> {
size: int;
get(index: int): T;
set(index: int, value: T): void;
}
struct LinkedList<T : any> {
head: T?;
tail: LinkedList<T>?;
init -> {
self.head = null;
self.tail = null;
}
}
impl List<T> for LinkedList<T> {
size -> {
if self.head == null {
return 0;
}
if self.tail == null {
return 1;
}
return 1 + self.tail.size();
}
get(index) -> {
if index == 0 {
return self.head;
}
return self.tail.get(index - 1);
}
set(index, value) -> {
if index == 0 {
self.head = value;
return;
}
if self.tail == null {
raise StringError(
"LinkedList<T>.set(...): index out of bounds",
);
}
self.tail.set(index - 1, value,);
}
}
fun foo -> "Hello World!";

View File

@ -84,15 +84,15 @@ innerStmt
} }
| varDecl { $ast = $varDecl.ast } | varDecl { $ast = $varDecl.ast }
| returnStmt { $ast = $returnStmt.ast } | returnStmt { $ast = $returnStmt.ast }
| raiseStmt { $ast = $raiseStmt.ast }
| ifStmt { $ast = $ifStmt.ast } | ifStmt { $ast = $ifStmt.ast }
| whileStmt { $ast = $whileStmt.ast }; | whileStmt { $ast = $whileStmt.ast };
varDecl varDecl
returns[AST.VarDecl ast = null as any]: returns[AST.VarDecl ast = null as any]:
'let' (name = ID) (':' typeName)? '=' rval = expr ';' { 'let' mut = 'mut'? (name = ID) (':' typeName)? '=' rval = expr ';' {
$ast = new AST.VarDecl( $ast = new AST.VarDecl(
this.getSourceRange($ctx), this.getSourceRange($ctx),
!!$ctx._mut,
$name.text!, $name.text!,
$ctx.typeName()?.ast ?? null, $ctx.typeName()?.ast ?? null,
$rval.ast, $rval.ast,
@ -101,10 +101,10 @@ varDecl
funDecl funDecl
returns[AST.FunDecl ast = null as any]: returns[AST.FunDecl ast = null as any]:
'fun' name = ID ( pub = 'pub'? 'fun' name = ID (
'(' (params += funParam (',' params += funParam)* ','?)? ')' '(' (params += funParam (',' params += funParam)* ','?)? ')'
)? (':' returnType = typeName)? '->' ( )? '->' returnTypeName = typeName '->' (
exprBody = expr ';' '=' exprBody = expr ';'
| blockBody = block | blockBody = block
) { ) {
let block: AST.Block; let block: AST.Block;
@ -115,9 +115,10 @@ funDecl
$ast = new AST.FunDecl( $ast = new AST.FunDecl(
this.getSourceRange($ctx), this.getSourceRange($ctx),
!!$ctx._pub,
$name.text!, $name.text!,
$ctx._returnType?.ast ?? null,
$params.map(p => p.ast), $params.map(p => p.ast),
$returnTypeName.ast,
block, block,
); );
}; };
@ -134,74 +135,72 @@ funParam
structDecl structDecl
returns[AST.StructDecl ast = null as any]: returns[AST.StructDecl ast = null as any]:
'struct' name = ID ( pub = 'pub'? 'struct' name = ID (
'<' typeParams += structTypeParam ( '<' structTypeParams += ID (',' structTypeParams += ID)* '>'
',' typeParams += structTypeParam )? '{' fields += memberField* methods += memberMethod* '}' {
)* '>'
)? '{' fields += structField* initializers += structInitializer* '}' {
$ast = new AST.StructDecl( $ast = new AST.StructDecl(
this.getSourceRange($ctx), this.getSourceRange($ctx),
!!$ctx._pub,
$name.text!, $name.text!,
$typeParams.map(p => p.ast), $structTypeParams.map(p => p.text),
$fields.map(f => f.ast), $fields.map(field => field.ast),
$initializers.map(i => i.ast), $methods.map(method => method.ast),
);
};
structField
returns[AST.StructField ast = null as any]:
name = ID ':' typeName ';' {
$ast = new AST.StructField(
this.getSourceRange($ctx),
$name.text!,
$typeName.ast,
);
};
structInitializer
returns[AST.StructInitializer ast = null as any]:
'init' (
'(' (params += funParam (',' params += funParam)* ','?)? ')'
)? '->' body = block {
$ast = new AST.StructInitializer(
this.getSourceRange($ctx),
$params.map(p => p.ast),
$body.ast,
);
};
structTypeParam
returns[AST.StructTypeParam ast = null as any]:
name = ID (':' bound = typeName)? {
$ast = new AST.StructTypeParam(
this.getSourceRange($ctx),
$name.text!,
$ctx._bound?.ast ?? null,
); );
}; };
traitDecl traitDecl
returns[AST.TraitDecl ast = null as any]: returns[AST.TraitDecl ast = null as any]:
'trait' name = ID ( pub = 'pub'? 'trait' name = ID (
'<' typeParams += traitTypeParam ( '<' traitTypeParams += ID (',' traitTypeParams += ID)* '>'
',' typeParams += traitTypeParam )? (
)* '>' ':' parents += namedOrGenericTypeName (
)? '{' attrs += traitAttr* '}' { ',' parents += namedOrGenericTypeName
)*
)? '{' methods += memberMethod* '}' {
$ast = new AST.TraitDecl( $ast = new AST.TraitDecl(
this.getSourceRange($ctx), this.getSourceRange($ctx),
!!$ctx._pub,
$name.text!, $name.text!,
$typeParams.map(tp => tp.ast), $traitTypeParams.map(tp => tp.text),
$attrs.map(attr => attr.ast), $parents.map(parent => parent.ast),
$methods.map(method => method.ast),
); );
}; };
traitAttr implDecl
returns[AST.TraitAttr ast = null as any]: returns[AST.ImplDecl ast = null as any]:
isConst = 'const'? name = ID ( 'impl' traitTypeName = namedOrGenericTypeName 'for' structName = qualifiedName (
'(' (params += funParam (',' params += funParam)* ','?)? ')' '<' structTypeParams += ID (',' structTypeParams += ID)* '>'
)? ':' returnType = typeName ( )? '{' methods += memberMethod* '}' {
'->' (exprBody = expr ';' | blockBody = block) $ast = new AST.ImplDecl(
| ';' this.getSourceRange($ctx),
$traitTypeName.ast,
$structName.text!,
$structTypeParams.map(p => p.text),
$methods.map(method => method.ast),
);
};
memberField
returns[AST.MemberField ast = null as any]:
pub = 'pub'? mut = 'mut'? name = ID ':' typeName ';' {
$ast = new AST.MemberField(
this.getSourceRange($ctx),
!!$ctx._pub,
!!$ctx._mut,
$name.text!,
$typeName.ast,
);
};
memberMethod
returns[AST.MemberMethod ast = null as any]:
pub = 'pub'? name = ID '(' (
params += funParam (',' params += funParam)* ','?
)? ')' '->' returnTypeName = typeName (
';'
| blockBody = block
| '=' exprBody = expr ';'
) { ) {
let block: AST.Block | null = null; let block: AST.Block | null = null;
if ($ctx._blockBody?.ast) block = $blockBody.ast; if ($ctx._blockBody?.ast) block = $blockBody.ast;
@ -209,61 +208,12 @@ traitAttr
new AST.ReturnStmt($exprBody.ast.sourceRange, $exprBody.ast), new AST.ReturnStmt($exprBody.ast.sourceRange, $exprBody.ast),
]); ]);
$ast = new AST.TraitAttr( $ast = new AST.MemberMethod(
this.getSourceRange($ctx), this.getSourceRange($ctx),
!!$isConst.text, !!$ctx._pub,
$name.text!, $name.text!,
$params.map(p => p.ast), $params.map(p => p.ast),
$returnType.ast, $returnTypeName.ast,
block,
);
};
traitTypeParam
returns[AST.TraitTypeParam ast = null as any]:
name = ID (':' bound = typeName)? {
$ast = new AST.TraitTypeParam(
this.getSourceRange($ctx),
$name.text!,
$ctx._bound?.ast ?? null,
);
};
implDecl
returns[AST.ImplDecl ast = null as any]:
'impl' traitName = qualifiedName (
'<' traitTypeArgs += typeArg (
',' traitTypeArgs += typeArg
)* '>'
)? 'for' structName = qualifiedName (
'<' structTypeParams += ID (',' structTypeParams += ID)* '>'
)? '{' attrs += implAttr* '}' {
$ast = new AST.ImplDecl(
this.getSourceRange($ctx),
$traitName.text!,
$traitTypeArgs.map(arg => arg.ast),
$structName.text!,
$structTypeParams.map(p => p.text),
$attrs.map(attr => attr.ast),
);
};
implAttr
returns[AST.ImplAttr ast = null as any]:
name = ID ('(' (params += ID (',' params += ID)* ','?)? ')')? '->' (
exprBody = expr ';'
| blockBody = block
) {
let block: AST.Block;
if ($ctx._blockBody?.ast) block = $blockBody.ast;
else block = new AST.Block($exprBody.ast.sourceRange, [
new AST.ReturnStmt($exprBody.ast.sourceRange, $exprBody.ast),
]);
$ast = new AST.ImplAttr(
this.getSourceRange($ctx),
$name.text!,
$params.map(p => p.text),
block, block,
); );
}; };
@ -298,23 +248,25 @@ ifStmt
); );
}; };
raiseStmt
returns[AST.RaiseStmt ast = null as any]:
'raise' value = expr ';' {
$ast = new AST.RaiseStmt(
this.getSourceRange($ctx),
$value.ast,
);
};
expr expr
returns[AST.Expr ast = null as any]: returns[AST.Expr ast = null as any]:
name = qualifiedName { $ast = new AST.Identifier(this.getSourceRange($ctx), $name.name) } name = qualifiedName {
| val = INT { $ast = new AST.IntExpr(this.getSourceRange($ctx), new Integer($val.text!)) } $ast = new AST.Identifier(this.getSourceRange($ctx), $name.name);
| val = FLOAT { $ast = new AST.FloatExpr(this.getSourceRange($ctx), new Float($val.text!)) } }
| val = STRING { $ast = new AST.StringExpr(this.getSourceRange($ctx), JSON.parse($val.text!)) } | val = INT {
| lhs = expr op = BINOP rhs = expr { $ast = new AST.IntExpr(this.getSourceRange($ctx), new Integer($val.text!));
$ast = new AST.BinExpr(this.getSourceRange($ctx), $op.text!, $lhs.ast, $rhs.ast) ; }
| val = FLOAT {
$ast = new AST.FloatExpr(this.getSourceRange($ctx), new Float($val.text!));
}
| val = STRING {
$ast = new AST.StringExpr(this.getSourceRange($ctx), JSON.parse($val.text!));
}
| unop = UNOP value = expr {
$ast = new AST.UnExpr(this.getSourceRange($ctx), $unop.text!, $value.ast);
}
| lhs = expr binop rhs = expr {
$ast = new AST.BinExpr(this.getSourceRange($ctx), $binop.value, $lhs.ast, $rhs.ast);
} }
| cond = expr '?' ifTrue = expr ':' ifFalse = expr { | cond = expr '?' ifTrue = expr ':' ifFalse = expr {
$ast = new AST.CondExpr(this.getSourceRange($ctx), $cond.ast, $ifTrue.ast, $ifFalse.ast); $ast = new AST.CondExpr(this.getSourceRange($ctx), $cond.ast, $ifTrue.ast, $ifFalse.ast);
@ -333,10 +285,9 @@ expr
$rval.ast, $rval.ast,
); );
} }
| '(' (params += funParam (',' params += funParam)* ','?)? ')' '->' ( | '(' (
exprBody = expr params += lambdaExprParam (',' params += lambdaExprParam)* ','?
| blockBody = block )? ')' '->' (exprBody = expr | blockBody = block) {
) {
let block: AST.Block; let block: AST.Block;
if ($ctx._blockBody?.ast) block = $blockBody.ast; if ($ctx._blockBody?.ast) block = $blockBody.ast;
else block = new AST.Block($exprBody.ast.sourceRange, [ else block = new AST.Block($exprBody.ast.sourceRange, [
@ -351,35 +302,71 @@ expr
} }
| '(' expr ')' { $ast = $expr.ast }; | '(' expr ')' { $ast = $expr.ast };
lambdaExprParam
returns[AST.LambdaParam ast = null as any]:
name = ID (':' typeName)? {
$ast = new AST.LambdaParam(
this.getSourceRange($ctx),
$name.text!,
$ctx.typeName()?.ast ?? null,
);
};
namedOrGenericTypeName
returns[(AST.NamedTypeName | AST.GenericTypeName) ast = null as any]:
namedTypeName { $ast = $namedTypeName.ast }
| genericTypeName { $ast = $genericTypeName.ast };
typeName typeName
returns[AST.TypeName ast = null as any]: returns[AST.TypeName ast = null as any]:
name = ID { $ast = new AST.NamedTypeName(this.getSourceRange($ctx), $name.text!) } (
| name = ID '<' typeArgs += typeArg (',' typeArgs += typeArg)* '>' { namedTypeName
| genericTypeName
| pointerTypeName
| nullableTypeName
| lambdaTypeName
) { $ast = ($ctx.getChild(0) as any).ast };
namedTypeName
returns[AST.NamedTypeName ast = null as any]:
name = ID {
$ast = new AST.NamedTypeName(
this.getSourceRange($ctx),
$name.text!,
);
};
genericTypeName
returns[AST.GenericTypeName ast = null as any]:
name = ID '<' typeArgs += typeName (',' typeArgs += typeName)* '>' {
$ast = new AST.GenericTypeName( $ast = new AST.GenericTypeName(
this.getSourceRange($ctx), this.getSourceRange($ctx),
$name.text!, $name.text!,
$typeArgs.map(arg => arg.ast), $typeArgs.map(arg => arg.ast),
); );
} };
| type_ = typeName '?' {
pointerTypeName
returns[AST.PointerTypeName ast = null as any]:
'&' (namedTypeName | genericTypeName) {
$ast = new AST.PointerTypeName(
this.getSourceRange($ctx),
$ctx.namedTypeName()?.ast || $ctx.genericTypeName()?.ast,
);
};
nullableTypeName
returns[AST.NullableTypeName ast = null as any]:
(pointerTypeName | lambdaTypeName) '?' {
$ast = new AST.NullableTypeName( $ast = new AST.NullableTypeName(
this.getSourceRange($ctx), this.getSourceRange($ctx),
$type_.ast, $ctx.pointerTypeName()?.ast || $ctx.lambdaTypeName()?.ast,
); );
} };
| type_ = typeName '[' ']' {
$ast = new AST.ArrayTypeName( lambdaTypeName
this.getSourceRange($ctx), returns[AST.LambdaTypeName ast = null as any]:
$type_.ast, '(' (
);
}
| '(' typeNames += typeName (',' typeNames += typeName)+ ','? ')' {
$ast = new AST.TupleTypeName(
this.getSourceRange($ctx),
$typeNames.map(typeName => typeName.ast),
);
}
| '(' (
params += lambdaTypeNameParam ( params += lambdaTypeNameParam (
',' params += lambdaTypeNameParam ',' params += lambdaTypeNameParam
)* ','? )* ','?
@ -393,8 +380,8 @@ typeName
lambdaTypeNameParam lambdaTypeNameParam
returns[[string | null, AST.TypeName] ast = null as any]: returns[[string | null, AST.TypeName] ast = null as any]:
(name = ID ':')? type_ = typeName { (name = ID ':')? typeName {
$ast = [$name.text ?? null, $type_.ast]; $ast = [$name.text ?? null, $ctx.typeName().ast];
}; };
typeArg typeArg
@ -407,6 +394,12 @@ qualifiedName
$name = $qualifiers.map(q => q.text); $name = $qualifiers.map(q => q.text);
}; };
binop
returns[string value = '']:
(BINOP | '<' | '>') { $value = $ctx.getText(); };
UNOP: '~' | '!';
BINOP: BINOP:
'+' '+'
| '-' | '-'
@ -423,10 +416,9 @@ BINOP:
| '??' | '??'
| '**' | '**'
| '==' | '=='
| '!='
| '>=' | '>='
| '<=' | '<=';
| '>'
| '<';
FLOAT: ('+' | '-')? ([0-9]+ '.' [0-9]* | [0-9]* '.' [0-9]+); FLOAT: ('+' | '-')? ([0-9]+ '.' [0-9]* | [0-9]* '.' [0-9]+);

View File

@ -2,7 +2,7 @@ import type { Block } from "./block";
import type { Expr } from "./expr"; import type { Expr } from "./expr";
import { Node, SourceRange } from "./node"; import { Node, SourceRange } from "./node";
import { Stmt } from "./stmt"; import { Stmt } from "./stmt";
import type { TypeName } from "./type-name"; import type { GenericTypeName, NamedTypeName, TypeName } from "./type-name";
import type { Visitor } from "./visitor"; import type { Visitor } from "./visitor";
export abstract class Decl extends Stmt { } export abstract class Decl extends Stmt { }
@ -10,6 +10,7 @@ export abstract class Decl extends Stmt { }
export class VarDecl extends Decl { export class VarDecl extends Decl {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isMut: boolean,
public name: string, public name: string,
public typeName: TypeName | null, public typeName: TypeName | null,
public value: Expr, public value: Expr,
@ -23,9 +24,10 @@ export class VarDecl extends Decl {
export class FunDecl extends Decl { export class FunDecl extends Decl {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isPub: boolean,
public name: string, public name: string,
public returnTypeName: TypeName | null,
public params: FunParam[], public params: FunParam[],
public returnTypeName: TypeName,
public body: Block, public body: Block,
) { super(sourceRange); } ) { super(sourceRange); }
@ -49,9 +51,11 @@ export class FunParam extends Node {
export class TraitDecl extends Decl { export class TraitDecl extends Decl {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isPub: boolean,
public name: string, public name: string,
public typeParams: TraitTypeParam[], public genericParams: string[],
public attrs: TraitAttr[], public parents: (NamedTypeName | GenericTypeName)[],
public methods: MemberMethod[],
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
@ -59,41 +63,13 @@ export class TraitDecl extends Decl {
} }
} }
export class TraitAttr extends Node {
constructor(
sourceRange: SourceRange,
public isConst: boolean,
public name: string,
public params: FunParam[],
public returnTypeName: TypeName,
public defaultBody: Block | null,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitTraitAttr(this);
}
}
export class TraitTypeParam extends Node {
constructor(
sourceRange: SourceRange,
public name: string,
public bound: TypeName | null,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitTraitTypeParam(this);
}
}
export class ImplDecl extends Decl { export class ImplDecl extends Decl {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public traitName: string, public traitTypeName: NamedTypeName | GenericTypeName,
public traitTypeArgs: TypeName[],
public structName: string, public structName: string,
public structTypeParams: string[], public structGenericParams: string[],
public attrs: ImplAttr[], public methods: MemberMethod[],
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
@ -101,26 +77,14 @@ export class ImplDecl extends Decl {
} }
} }
export class ImplAttr extends Decl {
constructor(
sourceRange: SourceRange,
public name: string,
public paramNames: string[],
public body: Block,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitImplAttr(this);
}
}
export class StructDecl extends Decl { export class StructDecl extends Decl {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isPub: boolean,
public name: string, public name: string,
public typeParams: StructTypeParam[], public genericParams: string[],
public fields: StructField[], public fields: MemberField[],
public initializers: StructInitializer[], public methods: MemberMethod[],
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
@ -128,38 +92,31 @@ export class StructDecl extends Decl {
} }
} }
export class StructField extends Node { export class MemberField extends Node {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isPub: boolean,
public isMut: boolean,
public name: string, public name: string,
public typeName: TypeName, public typeName: TypeName,
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitStructField(this); return visitor.visitMemberField(this);
} }
} }
export class StructInitializer extends Node { export class MemberMethod extends Node {
constructor(
sourceRange: SourceRange,
public params: FunParam[],
public body: Block,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitStructInitializer(this);
}
}
export class StructTypeParam extends Node {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public isPub: boolean,
public name: string, public name: string,
public bound: TypeName | null, public params: FunParam[],
public returnTypeName: TypeName,
public body: Block | null,
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitStructTypeParam(this); return visitor.visitMemberMethod(this);
} }
} }

View File

@ -3,6 +3,7 @@ import type { Visitor } from "./visitor";
import type { FunParam } from "./decl"; import type { FunParam } from "./decl";
import type { Block } from "./block"; import type { Block } from "./block";
import type { Float, Integer } from "~/const"; import type { Float, Integer } from "~/const";
import type { TypeName } from "./type-name";
export abstract class Expr extends Node { } export abstract class Expr extends Node { }
@ -46,6 +47,17 @@ export class StringExpr extends Expr {
} }
} }
export class UnExpr extends Expr {
constructor(
sourceRange: SourceRange,
public op: string,
public value: Expr,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitUnExpr(this);
}
}
export class BinExpr extends Expr { export class BinExpr extends Expr {
constructor( constructor(
@ -88,7 +100,7 @@ export class CondExpr extends Expr {
export class LambdaExpr extends Expr { export class LambdaExpr extends Expr {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public params: FunParam[], public params: LambdaParam[],
public body: Block, public body: Block,
) { super(sourceRange); } ) { super(sourceRange); }
@ -97,6 +109,18 @@ export class LambdaExpr extends Expr {
} }
} }
export class LambdaParam extends Node {
constructor(
sourceRange: SourceRange,
public name: string,
public typeName: TypeName | null,
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitLambdaParam(this);
}
}
export class AssignExpr extends Expr { export class AssignExpr extends Expr {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,

View File

@ -50,14 +50,3 @@ export class WhileStmt extends Stmt {
} }
} }
export class RaiseStmt extends Stmt {
constructor(
sourceRange: SourceRange,
public value: Expr
) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitRaiseStmt(this);
}
}

View File

@ -1,4 +1,3 @@
import type { Expr } from "./expr";
import { Node, SourceRange } from "./node"; import { Node, SourceRange } from "./node";
import type { Visitor } from "./visitor"; import type { Visitor } from "./visitor";
@ -38,14 +37,14 @@ export class NullableTypeName extends TypeName {
} }
} }
export class ArrayTypeName extends TypeName { export class PointerTypeName extends TypeName {
constructor( constructor(
sourceRange: SourceRange, sourceRange: SourceRange,
public typeName: TypeName, public typeName: TypeName,
) { super(sourceRange); } ) { super(sourceRange); }
accept<ResultT>(visitor: Visitor<ResultT>): ResultT { accept<ResultT>(visitor: Visitor<ResultT>): ResultT {
return visitor.visitArrayTypeName(this); return visitor.visitPointerTypeName(this);
} }
} }

View File

@ -1,9 +1,9 @@
import type { Block } from "./block"; import type { Block } from "./block";
import type { FunDecl, FunParam, ImplAttr, ImplDecl, StructDecl, StructField, StructInitializer, StructTypeParam, TraitAttr, TraitDecl, TraitTypeParam, VarDecl } from "./decl"; import type { FunDecl, FunParam, ImplDecl, MemberField, MemberMethod, StructDecl, TraitDecl, VarDecl } from "./decl";
import type { AssignExpr, BinExpr, CallExpr, CondExpr, FloatExpr, Identifier, IntExpr, LambdaExpr, StringExpr } from "./expr"; import type { AssignExpr, BinExpr, CallExpr, CondExpr, FloatExpr, Identifier, IntExpr, LambdaExpr, LambdaParam, StringExpr, UnExpr } from "./expr";
import type { ImportStmt, Module, ModuleDecl } from "./module"; import type { ImportStmt, Module, ModuleDecl } from "./module";
import { IfStmt, RaiseStmt, ReturnStmt, WhileStmt, type ExprStmt } from "./stmt"; import type { IfStmt, ReturnStmt, WhileStmt, ExprStmt } from "./stmt";
import type { ArrayTypeName, GenericTypeName, LambdaTypeName, NamedTypeName, NullableTypeName, TupleTypeName } from "./type-name"; import type { GenericTypeName, LambdaTypeName, NamedTypeName, NullableTypeName, PointerTypeName, TupleTypeName } from "./type-name";
export abstract class Visitor<ResultT = any> { export abstract class Visitor<ResultT = any> {
public abstract visitModule(module_: Module): ResultT; public abstract visitModule(module_: Module): ResultT;
@ -15,40 +15,38 @@ export abstract class Visitor<ResultT = any> {
public abstract visitReturnStmt(returnStmt: ReturnStmt): ResultT; public abstract visitReturnStmt(returnStmt: ReturnStmt): ResultT;
public abstract visitIfStmt(ifStmt: IfStmt): ResultT; public abstract visitIfStmt(ifStmt: IfStmt): ResultT;
public abstract visitWhileStmt(whileStmt: WhileStmt): ResultT; public abstract visitWhileStmt(whileStmt: WhileStmt): ResultT;
public abstract visitRaiseStmt(raiseStmt: RaiseStmt): ResultT;
public abstract visitVarDecl(varDecl: VarDecl): ResultT; public abstract visitVarDecl(varDecl: VarDecl): ResultT;
public abstract visitFunDecl(funDecl: FunDecl): ResultT; public abstract visitFunDecl(funDecl: FunDecl): ResultT;
public abstract visitFunParam(funParam: FunParam): ResultT; public abstract visitFunParam(funParam: FunParam): ResultT;
public abstract visitTraitDecl(traitDecl: TraitDecl): ResultT; public abstract visitTraitDecl(traitDecl: TraitDecl): ResultT;
public abstract visitTraitAttr(traitAttr: TraitAttr): ResultT;
public abstract visitTraitTypeParam(traitTypeParam: TraitTypeParam): ResultT;
public abstract visitImplDecl(implDecl: ImplDecl): ResultT; public abstract visitImplDecl(implDecl: ImplDecl): ResultT;
public abstract visitImplAttr(implAttr: ImplAttr): ResultT;
public abstract visitStructDecl(structDecl: StructDecl): ResultT; public abstract visitStructDecl(structDecl: StructDecl): ResultT;
public abstract visitStructField(structField: StructField): ResultT; public abstract visitMemberField(memberField: MemberField): ResultT;
public abstract visitStructTypeParam(structTypeParam: StructTypeParam): ResultT; public abstract visitMemberMethod(memberMethod: MemberMethod): ResultT;
public abstract visitStructInitializer(structInitializer: StructInitializer): ResultT;
public abstract visitIdentifier(identifier: Identifier): ResultT; public abstract visitIdentifier(identifier: Identifier): ResultT;
public abstract visitIntExpr(intExpr: IntExpr): ResultT; public abstract visitIntExpr(intExpr: IntExpr): ResultT;
public abstract visitFloatExpr(floatExpr: FloatExpr): ResultT; public abstract visitFloatExpr(floatExpr: FloatExpr): ResultT;
public abstract visitStringExpr(stringExpr: StringExpr): ResultT; public abstract visitStringExpr(stringExpr: StringExpr): ResultT;
public abstract visitUnExpr(unExpr: UnExpr): ResultT;
public abstract visitBinExpr(binExpr: BinExpr): ResultT; public abstract visitBinExpr(binExpr: BinExpr): ResultT;
public abstract visitCallExpr(callExpr: CallExpr): ResultT; public abstract visitCallExpr(callExpr: CallExpr): ResultT;
public abstract visitCondExpr(condExpr: CondExpr): ResultT; public abstract visitCondExpr(condExpr: CondExpr): ResultT;
public abstract visitLambdaExpr(lambdaExpr: LambdaExpr): ResultT; public abstract visitLambdaExpr(lambdaExpr: LambdaExpr): ResultT;
public abstract visitLambdaParam(lambdaParam: LambdaParam): ResultT;
public abstract visitAssignExpr(assignExpr: AssignExpr): ResultT; public abstract visitAssignExpr(assignExpr: AssignExpr): ResultT;
public abstract visitNamedTypeName(namedTypeName: NamedTypeName): ResultT; public abstract visitNamedTypeName(namedTypeName: NamedTypeName): ResultT;
public abstract visitGenericTypeName(genericTypeName: GenericTypeName): ResultT; public abstract visitGenericTypeName(genericTypeName: GenericTypeName): ResultT;
public abstract visitNullableTypeName(nullableTypeName: NullableTypeName): ResultT; public abstract visitNullableTypeName(nullableTypeName: NullableTypeName): ResultT;
public abstract visitArrayTypeName(arrayTypeName: ArrayTypeName): ResultT; public abstract visitPointerTypeName(pointerTypeName: PointerTypeName): ResultT;
public abstract visitTupleTypeName(tupleTypeName: TupleTypeName): ResultT; public abstract visitTupleTypeName(tupleTypeName: TupleTypeName): ResultT;
public abstract visitLambdaTypeName(lambdaTypeName: LambdaTypeName): ResultT; public abstract visitLambdaTypeName(lambdaTypeName: LambdaTypeName): ResultT;
} }
export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> { export class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
public visitModule(module_: Module): ResultT { public visitModule(module_: Module): ResultT {
module_.imports.forEach((import_) => import_.accept(this)); module_.imports.forEach((import_) => import_.accept(this));
module_.decls.forEach((decl) => decl.accept(this)); module_.decls.forEach((decl) => decl.accept(this));
@ -91,11 +89,6 @@ export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
return null as any; return null as any;
} }
public visitRaiseStmt(raiseStmt: RaiseStmt): ResultT {
raiseStmt.value.accept(this);
return null as any;
}
public visitVarDecl(varDecl: VarDecl): ResultT { public visitVarDecl(varDecl: VarDecl): ResultT {
varDecl.typeName?.accept(this); varDecl.typeName?.accept(this);
varDecl.value.accept(this); varDecl.value.accept(this);
@ -115,53 +108,30 @@ export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
} }
public visitTraitDecl(traitDecl: TraitDecl): ResultT { public visitTraitDecl(traitDecl: TraitDecl): ResultT {
traitDecl.typeParams.forEach((typeParam) => typeParam.accept(this)); traitDecl.methods.forEach((method) => method.accept(this));
traitDecl.attrs.forEach((attr) => attr.accept(this));
return null as any;
}
public visitTraitAttr(traitAttr: TraitAttr): ResultT {
traitAttr.params.forEach((param) => param.accept(this));
traitAttr.returnTypeName.accept(this);
traitAttr.defaultBody?.accept(this);
return null as any;
}
public visitTraitTypeParam(traitTypeParam: TraitTypeParam): ResultT {
traitTypeParam.bound?.accept(this);
return null as any; return null as any;
} }
public visitImplDecl(implDecl: ImplDecl): ResultT { public visitImplDecl(implDecl: ImplDecl): ResultT {
implDecl.traitTypeArgs.forEach((traitTypeArg) => traitTypeArg.accept(this)); implDecl.methods.forEach((attr) => attr.accept(this));
implDecl.attrs.forEach((attr) => attr.accept(this));
return null as any;
}
public visitImplAttr(implAttr: ImplAttr): ResultT {
implAttr.body.accept(this);
return null as any; return null as any;
} }
public visitStructDecl(structDecl: StructDecl): ResultT { public visitStructDecl(structDecl: StructDecl): ResultT {
structDecl.typeParams.forEach((typeParam) => typeParam.accept(this));
structDecl.fields.forEach((field) => field.accept(this)); structDecl.fields.forEach((field) => field.accept(this));
structDecl.methods.forEach((method) => method.accept(this));
return null as any; return null as any;
} }
public visitStructTypeParam(structTypeParam: StructTypeParam): ResultT { public visitMemberField(memberField: MemberField): ResultT {
structTypeParam.bound?.accept(this); memberField.typeName.accept(this);
return null as any; return null as any;
} }
public visitStructField(structField: StructField): ResultT { public visitMemberMethod(memberMethod: MemberMethod): ResultT {
structField.typeName.accept(this); memberMethod.params.forEach((param) => param.accept(this));
return null as any; memberMethod.returnTypeName?.accept(this);
} memberMethod.body?.accept(this);
public visitStructInitializer(structInitializer: StructInitializer): ResultT {
structInitializer.params.forEach((param) => param.accept(this));
structInitializer.body.accept(this);
return null as any; return null as any;
} }
@ -181,6 +151,11 @@ export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
return null as any; return null as any;
} }
public visitUnExpr(unExpr: UnExpr): ResultT {
unExpr.value.accept(this);
return null as any;
}
public visitBinExpr(binExpr: BinExpr): ResultT { public visitBinExpr(binExpr: BinExpr): ResultT {
binExpr.lhs.accept(this); binExpr.lhs.accept(this);
binExpr.rhs.accept(this); binExpr.rhs.accept(this);
@ -206,6 +181,11 @@ export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
return null as any; return null as any;
} }
public visitLambdaParam(lambdaParam: LambdaParam): ResultT {
lambdaParam.typeName?.accept(this);
return null as any;
}
public visitAssignExpr(assignExpr: AssignExpr): ResultT { public visitAssignExpr(assignExpr: AssignExpr): ResultT {
assignExpr.lval.accept(this); assignExpr.lval.accept(this);
assignExpr.rval.accept(this); assignExpr.rval.accept(this);
@ -226,8 +206,8 @@ export abstract class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
return null as any; return null as any;
} }
public visitArrayTypeName(arrayTypeName: ArrayTypeName): ResultT { public visitPointerTypeName(pointerTypeName: PointerTypeName): ResultT {
arrayTypeName.typeName.accept(this); pointerTypeName.typeName.accept(this);
return null as any; return null as any;
} }

View File

@ -0,0 +1,8 @@
import type { Type } from "./type";
export class Symbol {
constructor(
public name: string,
public type: Type,
) { }
}

View File

@ -1,8 +1,10 @@
import { inspect } from "bun"; import { inspect } from "bun";
import { parseModule } from "./parser"; import { parseModule } from "./parser";
import { printErrors } from "./errors"; import { hasErrors, printErrors } from "./errors";
import AST from "./frontend/ast";
const module = parseModule('examples/test.plsm'); const module = parseModule('examples/LinkedList.plsm');
console.log(inspect(module, { depth: 1000, colors: false })); console.log(inspect(module, { depth: 1000, colors: false }));
printErrors(); printErrors();
module.accept(new AST.BaseVisitor());