From 63ab8998d44f97bede40ea6e20b1a059a0e1065b Mon Sep 17 00:00:00 2001 From: Ludwig Lehnert Date: Wed, 5 Mar 2025 17:02:04 +0100 Subject: [PATCH] updated grammar; better LinkedList example --- examples/LinkedList.plsm | 169 +++++++++++++++++ examples/heap.plsm | 25 +++ examples/test.plsm | 70 ------- src/antlr/plsm.g4 | 302 +++++++++++++++---------------- src/frontend/ast/decl.ts | 93 +++------- src/frontend/ast/expr.ts | 26 ++- src/frontend/ast/stmt.ts | 11 -- src/frontend/ast/type-name.ts | 5 +- src/frontend/ast/visitor.ts | 84 ++++----- src/frontend/semantics/symbol.ts | 8 + src/main.ts | 8 +- 11 files changed, 438 insertions(+), 363 deletions(-) create mode 100644 examples/LinkedList.plsm create mode 100644 examples/heap.plsm delete mode 100644 examples/test.plsm diff --git a/examples/LinkedList.plsm b/examples/LinkedList.plsm new file mode 100644 index 0000000..b0940da --- /dev/null +++ b/examples/LinkedList.plsm @@ -0,0 +1,169 @@ +module test; + +import stdlib/io; +import stdlib/heap; +import stdlib/err; + +trait Collection { + 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(fn: (&T) -> &S) -> Collection; + // filter(fn: (&T) -> bool) -> Collection; +} + +trait Queue : Collection { + put(item: &T) -> void; + take() -> &T; + poll() -> &T?; + peek() -> &T?; +} + +trait Stack : Collection { + push(item: &T) -> void; + pop() -> &T; + peek() -> &T?; +} + +struct LinkedList { + pub mut head: &T?; + pub mut tail: &LinkedList?; + mut size: u64; + + init() -> void { + self.head = null; + self.tail = null; + self.size = 0; + } +} + +impl Collection for LinkedList { + 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 for LinkedList { + 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; +} diff --git a/examples/heap.plsm b/examples/heap.plsm new file mode 100644 index 0000000..92c8e1d --- /dev/null +++ b/examples/heap.plsm @@ -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 { + ptr: &T; + + ([])(index: u64) { + + } +} \ No newline at end of file diff --git a/examples/test.plsm b/examples/test.plsm deleted file mode 100644 index 3c288ca..0000000 --- a/examples/test.plsm +++ /dev/null @@ -1,70 +0,0 @@ -module test; - -import stdlib/io; - -fun main -> { - io.println(foo() + 10); -} - -trait Expr { - visit(visitor: Visitor): T; -} - -trait ExprVisitor { - visitString(string: String): T; -} - -trait List { - size: int; - get(index: int): T; - set(index: int, value: T): void; -} - -struct LinkedList { - head: T?; - tail: LinkedList?; - - init -> { - self.head = null; - self.tail = null; - } -} - -impl List for LinkedList { - 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.set(...): index out of bounds", - ); - } - - self.tail.set(index - 1, value,); - } -} - -fun foo -> "Hello World!"; diff --git a/src/antlr/plsm.g4 b/src/antlr/plsm.g4 index 89065dc..0684811 100644 --- a/src/antlr/plsm.g4 +++ b/src/antlr/plsm.g4 @@ -84,15 +84,15 @@ innerStmt } | varDecl { $ast = $varDecl.ast } | returnStmt { $ast = $returnStmt.ast } - | raiseStmt { $ast = $raiseStmt.ast } | ifStmt { $ast = $ifStmt.ast } | whileStmt { $ast = $whileStmt.ast }; varDecl 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( this.getSourceRange($ctx), + !!$ctx._mut, $name.text!, $ctx.typeName()?.ast ?? null, $rval.ast, @@ -101,10 +101,10 @@ varDecl funDecl returns[AST.FunDecl ast = null as any]: - 'fun' name = ID ( + pub = 'pub'? 'fun' name = ID ( '(' (params += funParam (',' params += funParam)* ','?)? ')' - )? (':' returnType = typeName)? '->' ( - exprBody = expr ';' + )? '->' returnTypeName = typeName '->' ( + '=' exprBody = expr ';' | blockBody = block ) { let block: AST.Block; @@ -115,9 +115,10 @@ funDecl $ast = new AST.FunDecl( this.getSourceRange($ctx), + !!$ctx._pub, $name.text!, - $ctx._returnType?.ast ?? null, $params.map(p => p.ast), + $returnTypeName.ast, block, ); }; @@ -134,74 +135,72 @@ funParam structDecl returns[AST.StructDecl ast = null as any]: - 'struct' name = ID ( - '<' typeParams += structTypeParam ( - ',' typeParams += structTypeParam - )* '>' - )? '{' fields += structField* initializers += structInitializer* '}' { + pub = 'pub'? 'struct' name = ID ( + '<' structTypeParams += ID (',' structTypeParams += ID)* '>' + )? '{' fields += memberField* methods += memberMethod* '}' { $ast = new AST.StructDecl( this.getSourceRange($ctx), + !!$ctx._pub, $name.text!, - $typeParams.map(p => p.ast), - $fields.map(f => f.ast), - $initializers.map(i => i.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, + $structTypeParams.map(p => p.text), + $fields.map(field => field.ast), + $methods.map(method => method.ast), ); }; traitDecl returns[AST.TraitDecl ast = null as any]: - 'trait' name = ID ( - '<' typeParams += traitTypeParam ( - ',' typeParams += traitTypeParam - )* '>' - )? '{' attrs += traitAttr* '}' { + pub = 'pub'? 'trait' name = ID ( + '<' traitTypeParams += ID (',' traitTypeParams += ID)* '>' + )? ( + ':' parents += namedOrGenericTypeName ( + ',' parents += namedOrGenericTypeName + )* + )? '{' methods += memberMethod* '}' { $ast = new AST.TraitDecl( this.getSourceRange($ctx), + !!$ctx._pub, $name.text!, - $typeParams.map(tp => tp.ast), - $attrs.map(attr => attr.ast), + $traitTypeParams.map(tp => tp.text), + $parents.map(parent => parent.ast), + $methods.map(method => method.ast), ); }; -traitAttr - returns[AST.TraitAttr ast = null as any]: - isConst = 'const'? name = ID ( - '(' (params += funParam (',' params += funParam)* ','?)? ')' - )? ':' returnType = typeName ( - '->' (exprBody = expr ';' | blockBody = block) - | ';' +implDecl + returns[AST.ImplDecl ast = null as any]: + 'impl' traitTypeName = namedOrGenericTypeName 'for' structName = qualifiedName ( + '<' structTypeParams += ID (',' structTypeParams += ID)* '>' + )? '{' methods += memberMethod* '}' { + $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; if ($ctx._blockBody?.ast) block = $blockBody.ast; @@ -209,61 +208,12 @@ traitAttr new AST.ReturnStmt($exprBody.ast.sourceRange, $exprBody.ast), ]); - $ast = new AST.TraitAttr( + $ast = new AST.MemberMethod( this.getSourceRange($ctx), - !!$isConst.text, + !!$ctx._pub, $name.text!, $params.map(p => p.ast), - $returnType.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), + $returnTypeName.ast, 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 returns[AST.Expr ast = null as any]: - name = qualifiedName { $ast = new AST.Identifier(this.getSourceRange($ctx), $name.name) } - | val = INT { $ast = new AST.IntExpr(this.getSourceRange($ctx), new Integer($val.text!)) } - | 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!)) } - | lhs = expr op = BINOP rhs = expr { - $ast = new AST.BinExpr(this.getSourceRange($ctx), $op.text!, $lhs.ast, $rhs.ast) ; + name = qualifiedName { + $ast = new AST.Identifier(this.getSourceRange($ctx), $name.name); + } + | val = INT { + $ast = new AST.IntExpr(this.getSourceRange($ctx), new Integer($val.text!)); + } + | 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 { $ast = new AST.CondExpr(this.getSourceRange($ctx), $cond.ast, $ifTrue.ast, $ifFalse.ast); @@ -333,10 +285,9 @@ expr $rval.ast, ); } - | '(' (params += funParam (',' params += funParam)* ','?)? ')' '->' ( - exprBody = expr - | blockBody = block - ) { + | '(' ( + params += lambdaExprParam (',' params += lambdaExprParam)* ','? + )? ')' '->' (exprBody = expr | blockBody = block) { let block: AST.Block; if ($ctx._blockBody?.ast) block = $blockBody.ast; else block = new AST.Block($exprBody.ast.sourceRange, [ @@ -351,35 +302,71 @@ expr } | '(' 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 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( this.getSourceRange($ctx), $name.text!, $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( this.getSourceRange($ctx), - $type_.ast, + $ctx.pointerTypeName()?.ast || $ctx.lambdaTypeName()?.ast, ); - } - | type_ = typeName '[' ']' { - $ast = new AST.ArrayTypeName( - this.getSourceRange($ctx), - $type_.ast, - ); - } - | '(' typeNames += typeName (',' typeNames += typeName)+ ','? ')' { - $ast = new AST.TupleTypeName( - this.getSourceRange($ctx), - $typeNames.map(typeName => typeName.ast), - ); - } - | '(' ( + }; + +lambdaTypeName + returns[AST.LambdaTypeName ast = null as any]: + '(' ( params += lambdaTypeNameParam ( ',' params += lambdaTypeNameParam )* ','? @@ -393,8 +380,8 @@ typeName lambdaTypeNameParam returns[[string | null, AST.TypeName] ast = null as any]: - (name = ID ':')? type_ = typeName { - $ast = [$name.text ?? null, $type_.ast]; + (name = ID ':')? typeName { + $ast = [$name.text ?? null, $ctx.typeName().ast]; }; typeArg @@ -407,6 +394,12 @@ qualifiedName $name = $qualifiers.map(q => q.text); }; +binop + returns[string value = '']: + (BINOP | '<' | '>') { $value = $ctx.getText(); }; + +UNOP: '~' | '!'; + BINOP: '+' | '-' @@ -423,10 +416,9 @@ BINOP: | '??' | '**' | '==' + | '!=' | '>=' - | '<=' - | '>' - | '<'; + | '<='; FLOAT: ('+' | '-')? ([0-9]+ '.' [0-9]* | [0-9]* '.' [0-9]+); diff --git a/src/frontend/ast/decl.ts b/src/frontend/ast/decl.ts index 8ff0450..53fe354 100644 --- a/src/frontend/ast/decl.ts +++ b/src/frontend/ast/decl.ts @@ -2,7 +2,7 @@ import type { Block } from "./block"; import type { Expr } from "./expr"; import { Node, SourceRange } from "./node"; import { Stmt } from "./stmt"; -import type { TypeName } from "./type-name"; +import type { GenericTypeName, NamedTypeName, TypeName } from "./type-name"; import type { Visitor } from "./visitor"; export abstract class Decl extends Stmt { } @@ -10,6 +10,7 @@ export abstract class Decl extends Stmt { } export class VarDecl extends Decl { constructor( sourceRange: SourceRange, + public isMut: boolean, public name: string, public typeName: TypeName | null, public value: Expr, @@ -23,9 +24,10 @@ export class VarDecl extends Decl { export class FunDecl extends Decl { constructor( sourceRange: SourceRange, + public isPub: boolean, public name: string, - public returnTypeName: TypeName | null, public params: FunParam[], + public returnTypeName: TypeName, public body: Block, ) { super(sourceRange); } @@ -49,9 +51,11 @@ export class FunParam extends Node { export class TraitDecl extends Decl { constructor( sourceRange: SourceRange, + public isPub: boolean, public name: string, - public typeParams: TraitTypeParam[], - public attrs: TraitAttr[], + public genericParams: string[], + public parents: (NamedTypeName | GenericTypeName)[], + public methods: MemberMethod[], ) { super(sourceRange); } accept(visitor: Visitor): 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(visitor: Visitor): ResultT { - return visitor.visitTraitAttr(this); - } -} - -export class TraitTypeParam extends Node { - constructor( - sourceRange: SourceRange, - public name: string, - public bound: TypeName | null, - ) { super(sourceRange); } - - accept(visitor: Visitor): ResultT { - return visitor.visitTraitTypeParam(this); - } -} - export class ImplDecl extends Decl { constructor( sourceRange: SourceRange, - public traitName: string, - public traitTypeArgs: TypeName[], + public traitTypeName: NamedTypeName | GenericTypeName, public structName: string, - public structTypeParams: string[], - public attrs: ImplAttr[], + public structGenericParams: string[], + public methods: MemberMethod[], ) { super(sourceRange); } accept(visitor: Visitor): 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(visitor: Visitor): ResultT { - return visitor.visitImplAttr(this); - } -} - export class StructDecl extends Decl { constructor( sourceRange: SourceRange, + public isPub: boolean, public name: string, - public typeParams: StructTypeParam[], - public fields: StructField[], - public initializers: StructInitializer[], + public genericParams: string[], + public fields: MemberField[], + public methods: MemberMethod[], ) { super(sourceRange); } accept(visitor: Visitor): ResultT { @@ -128,38 +92,31 @@ export class StructDecl extends Decl { } } -export class StructField extends Node { +export class MemberField extends Node { constructor( sourceRange: SourceRange, + public isPub: boolean, + public isMut: boolean, public name: string, public typeName: TypeName, ) { super(sourceRange); } accept(visitor: Visitor): ResultT { - return visitor.visitStructField(this); + return visitor.visitMemberField(this); } } -export class StructInitializer extends Node { - constructor( - sourceRange: SourceRange, - public params: FunParam[], - public body: Block, - ) { super(sourceRange); } - - accept(visitor: Visitor): ResultT { - return visitor.visitStructInitializer(this); - } -} - -export class StructTypeParam extends Node { +export class MemberMethod extends Node { constructor( sourceRange: SourceRange, + public isPub: boolean, public name: string, - public bound: TypeName | null, + public params: FunParam[], + public returnTypeName: TypeName, + public body: Block | null, ) { super(sourceRange); } accept(visitor: Visitor): ResultT { - return visitor.visitStructTypeParam(this); + return visitor.visitMemberMethod(this); } } diff --git a/src/frontend/ast/expr.ts b/src/frontend/ast/expr.ts index ba72718..4f2e38d 100644 --- a/src/frontend/ast/expr.ts +++ b/src/frontend/ast/expr.ts @@ -3,6 +3,7 @@ import type { Visitor } from "./visitor"; import type { FunParam } from "./decl"; import type { Block } from "./block"; import type { Float, Integer } from "~/const"; +import type { TypeName } from "./type-name"; 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(visitor: Visitor): ResultT { + return visitor.visitUnExpr(this); + } +} export class BinExpr extends Expr { constructor( @@ -88,7 +100,7 @@ export class CondExpr extends Expr { export class LambdaExpr extends Expr { constructor( sourceRange: SourceRange, - public params: FunParam[], + public params: LambdaParam[], public body: Block, ) { 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(visitor: Visitor): ResultT { + return visitor.visitLambdaParam(this); + } +} + export class AssignExpr extends Expr { constructor( sourceRange: SourceRange, diff --git a/src/frontend/ast/stmt.ts b/src/frontend/ast/stmt.ts index 28e19dc..7eb5ea0 100644 --- a/src/frontend/ast/stmt.ts +++ b/src/frontend/ast/stmt.ts @@ -50,14 +50,3 @@ export class WhileStmt extends Stmt { } } -export class RaiseStmt extends Stmt { - constructor( - sourceRange: SourceRange, - public value: Expr - ) { super(sourceRange); } - - accept(visitor: Visitor): ResultT { - return visitor.visitRaiseStmt(this); - } -} - diff --git a/src/frontend/ast/type-name.ts b/src/frontend/ast/type-name.ts index a86abeb..5e83a59 100644 --- a/src/frontend/ast/type-name.ts +++ b/src/frontend/ast/type-name.ts @@ -1,4 +1,3 @@ -import type { Expr } from "./expr"; import { Node, SourceRange } from "./node"; 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( sourceRange: SourceRange, public typeName: TypeName, ) { super(sourceRange); } accept(visitor: Visitor): ResultT { - return visitor.visitArrayTypeName(this); + return visitor.visitPointerTypeName(this); } } diff --git a/src/frontend/ast/visitor.ts b/src/frontend/ast/visitor.ts index 4137ed4..4e5b97c 100644 --- a/src/frontend/ast/visitor.ts +++ b/src/frontend/ast/visitor.ts @@ -1,9 +1,9 @@ import type { Block } from "./block"; -import type { FunDecl, FunParam, ImplAttr, ImplDecl, StructDecl, StructField, StructInitializer, StructTypeParam, TraitAttr, TraitDecl, TraitTypeParam, VarDecl } from "./decl"; -import type { AssignExpr, BinExpr, CallExpr, CondExpr, FloatExpr, Identifier, IntExpr, LambdaExpr, StringExpr } from "./expr"; +import type { FunDecl, FunParam, ImplDecl, MemberField, MemberMethod, StructDecl, TraitDecl, VarDecl } from "./decl"; +import type { AssignExpr, BinExpr, CallExpr, CondExpr, FloatExpr, Identifier, IntExpr, LambdaExpr, LambdaParam, StringExpr, UnExpr } from "./expr"; import type { ImportStmt, Module, ModuleDecl } from "./module"; -import { IfStmt, RaiseStmt, ReturnStmt, WhileStmt, type ExprStmt } from "./stmt"; -import type { ArrayTypeName, GenericTypeName, LambdaTypeName, NamedTypeName, NullableTypeName, TupleTypeName } from "./type-name"; +import type { IfStmt, ReturnStmt, WhileStmt, ExprStmt } from "./stmt"; +import type { GenericTypeName, LambdaTypeName, NamedTypeName, NullableTypeName, PointerTypeName, TupleTypeName } from "./type-name"; export abstract class Visitor { public abstract visitModule(module_: Module): ResultT; @@ -15,40 +15,38 @@ export abstract class Visitor { public abstract visitReturnStmt(returnStmt: ReturnStmt): ResultT; public abstract visitIfStmt(ifStmt: IfStmt): ResultT; public abstract visitWhileStmt(whileStmt: WhileStmt): ResultT; - public abstract visitRaiseStmt(raiseStmt: RaiseStmt): ResultT; public abstract visitVarDecl(varDecl: VarDecl): ResultT; public abstract visitFunDecl(funDecl: FunDecl): ResultT; public abstract visitFunParam(funParam: FunParam): 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 visitImplAttr(implAttr: ImplAttr): ResultT; public abstract visitStructDecl(structDecl: StructDecl): ResultT; - public abstract visitStructField(structField: StructField): ResultT; - public abstract visitStructTypeParam(structTypeParam: StructTypeParam): ResultT; - public abstract visitStructInitializer(structInitializer: StructInitializer): ResultT; + public abstract visitMemberField(memberField: MemberField): ResultT; + public abstract visitMemberMethod(memberMethod: MemberMethod): ResultT; + public abstract visitIdentifier(identifier: Identifier): ResultT; public abstract visitIntExpr(intExpr: IntExpr): ResultT; public abstract visitFloatExpr(floatExpr: FloatExpr): ResultT; public abstract visitStringExpr(stringExpr: StringExpr): ResultT; + public abstract visitUnExpr(unExpr: UnExpr): ResultT; public abstract visitBinExpr(binExpr: BinExpr): ResultT; public abstract visitCallExpr(callExpr: CallExpr): ResultT; public abstract visitCondExpr(condExpr: CondExpr): ResultT; public abstract visitLambdaExpr(lambdaExpr: LambdaExpr): ResultT; + public abstract visitLambdaParam(lambdaParam: LambdaParam): ResultT; public abstract visitAssignExpr(assignExpr: AssignExpr): ResultT; public abstract visitNamedTypeName(namedTypeName: NamedTypeName): ResultT; public abstract visitGenericTypeName(genericTypeName: GenericTypeName): 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 visitLambdaTypeName(lambdaTypeName: LambdaTypeName): ResultT; } -export abstract class BaseVisitor implements Visitor { +export class BaseVisitor implements Visitor { public visitModule(module_: Module): ResultT { module_.imports.forEach((import_) => import_.accept(this)); module_.decls.forEach((decl) => decl.accept(this)); @@ -91,11 +89,6 @@ export abstract class BaseVisitor implements Visitor { return null as any; } - public visitRaiseStmt(raiseStmt: RaiseStmt): ResultT { - raiseStmt.value.accept(this); - return null as any; - } - public visitVarDecl(varDecl: VarDecl): ResultT { varDecl.typeName?.accept(this); varDecl.value.accept(this); @@ -115,53 +108,30 @@ export abstract class BaseVisitor implements Visitor { } public visitTraitDecl(traitDecl: TraitDecl): ResultT { - traitDecl.typeParams.forEach((typeParam) => typeParam.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); + traitDecl.methods.forEach((method) => method.accept(this)); return null as any; } public visitImplDecl(implDecl: ImplDecl): ResultT { - implDecl.traitTypeArgs.forEach((traitTypeArg) => traitTypeArg.accept(this)); - implDecl.attrs.forEach((attr) => attr.accept(this)); - return null as any; - } - - public visitImplAttr(implAttr: ImplAttr): ResultT { - implAttr.body.accept(this); + implDecl.methods.forEach((attr) => attr.accept(this)); return null as any; } public visitStructDecl(structDecl: StructDecl): ResultT { - structDecl.typeParams.forEach((typeParam) => typeParam.accept(this)); structDecl.fields.forEach((field) => field.accept(this)); + structDecl.methods.forEach((method) => method.accept(this)); return null as any; } - public visitStructTypeParam(structTypeParam: StructTypeParam): ResultT { - structTypeParam.bound?.accept(this); + public visitMemberField(memberField: MemberField): ResultT { + memberField.typeName.accept(this); return null as any; } - public visitStructField(structField: StructField): ResultT { - structField.typeName.accept(this); - return null as any; - } - - public visitStructInitializer(structInitializer: StructInitializer): ResultT { - structInitializer.params.forEach((param) => param.accept(this)); - structInitializer.body.accept(this); + public visitMemberMethod(memberMethod: MemberMethod): ResultT { + memberMethod.params.forEach((param) => param.accept(this)); + memberMethod.returnTypeName?.accept(this); + memberMethod.body?.accept(this); return null as any; } @@ -181,6 +151,11 @@ export abstract class BaseVisitor implements Visitor { return null as any; } + public visitUnExpr(unExpr: UnExpr): ResultT { + unExpr.value.accept(this); + return null as any; + } + public visitBinExpr(binExpr: BinExpr): ResultT { binExpr.lhs.accept(this); binExpr.rhs.accept(this); @@ -206,6 +181,11 @@ export abstract class BaseVisitor implements Visitor { return null as any; } + public visitLambdaParam(lambdaParam: LambdaParam): ResultT { + lambdaParam.typeName?.accept(this); + return null as any; + } + public visitAssignExpr(assignExpr: AssignExpr): ResultT { assignExpr.lval.accept(this); assignExpr.rval.accept(this); @@ -226,8 +206,8 @@ export abstract class BaseVisitor implements Visitor { return null as any; } - public visitArrayTypeName(arrayTypeName: ArrayTypeName): ResultT { - arrayTypeName.typeName.accept(this); + public visitPointerTypeName(pointerTypeName: PointerTypeName): ResultT { + pointerTypeName.typeName.accept(this); return null as any; } diff --git a/src/frontend/semantics/symbol.ts b/src/frontend/semantics/symbol.ts index e69de29..9e64fd4 100644 --- a/src/frontend/semantics/symbol.ts +++ b/src/frontend/semantics/symbol.ts @@ -0,0 +1,8 @@ +import type { Type } from "./type"; + +export class Symbol { + constructor( + public name: string, + public type: Type, + ) { } +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 3ada3b0..6c3a3ce 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,10 @@ import { inspect } from "bun"; 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 })); -printErrors(); \ No newline at end of file +printErrors(); +module.accept(new AST.BaseVisitor()); \ No newline at end of file