updated grammar; better LinkedList example
This commit is contained in:
parent
3317626540
commit
63ab8998d4
169
examples/LinkedList.plsm
Normal file
169
examples/LinkedList.plsm
Normal 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
25
examples/heap.plsm
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
@ -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!";
|
@ -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]+);
|
||||
|
||||
|
@ -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<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 {
|
||||
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<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 {
|
||||
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<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(
|
||||
sourceRange: SourceRange,
|
||||
public isPub: boolean,
|
||||
public isMut: boolean,
|
||||
public name: string,
|
||||
public typeName: TypeName,
|
||||
) { super(sourceRange); }
|
||||
|
||||
accept<ResultT>(visitor: Visitor<ResultT>): 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<ResultT>(visitor: Visitor<ResultT>): 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<ResultT>(visitor: Visitor<ResultT>): ResultT {
|
||||
return visitor.visitStructTypeParam(this);
|
||||
return visitor.visitMemberMethod(this);
|
||||
}
|
||||
}
|
||||
|
@ -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<ResultT>(visitor: Visitor<ResultT>): 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<ResultT>(visitor: Visitor<ResultT>): ResultT {
|
||||
return visitor.visitLambdaParam(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class AssignExpr extends Expr {
|
||||
constructor(
|
||||
sourceRange: SourceRange,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ResultT>(visitor: Visitor<ResultT>): ResultT {
|
||||
return visitor.visitArrayTypeName(this);
|
||||
return visitor.visitPointerTypeName(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ResultT = any> {
|
||||
public abstract visitModule(module_: Module): ResultT;
|
||||
@ -15,40 +15,38 @@ export abstract class Visitor<ResultT = any> {
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
export class BaseVisitor<ResultT = any> implements Visitor<ResultT> {
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
}
|
||||
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
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<ResultT = any> implements Visitor<ResultT> {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
import type { Type } from "./type";
|
||||
|
||||
export class Symbol {
|
||||
constructor(
|
||||
public name: string,
|
||||
public type: Type,
|
||||
) { }
|
||||
}
|
@ -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();
|
||||
module.accept(new AST.BaseVisitor());
|
Loading…
x
Reference in New Issue
Block a user