add array syntax
All checks were successful
Check / Explore-Gitea-Actions (push) Successful in 7s

This commit is contained in:
sfja 2026-03-12 00:13:33 +01:00
parent 21e569e9ff
commit 6620dbcace
6 changed files with 43 additions and 2 deletions

View File

@ -80,6 +80,8 @@ export class Node {
return visit();
case "IntExpr":
return visit();
case "ArrayExpr":
return visit(...k.values);
case "CallExpr":
return visit(k.expr, ...k.args);
case "UnaryExpr":
@ -115,6 +117,7 @@ export type NodeKind =
| { tag: "Param"; ident: string; ty: Node | null }
| { tag: "IdentExpr"; ident: string }
| { tag: "IntExpr"; value: number }
| { tag: "ArrayExpr"; values: Node[] }
| { tag: "CallExpr"; expr: Node; args: Node[] }
| { tag: "UnaryExpr"; op: UnaryOp; expr: Node; tok: string }
| { tag: "BinaryExpr"; op: BinaryOp; left: Node; right: Node; tok: string }

View File

@ -80,6 +80,24 @@ export class Checker {
return Ty.Int;
}
if (node.is("ArrayExpr")) {
let ty: Ty | null = null;
for (const value of node.kind.values) {
const valueTy = this.check(value);
if (ty) {
this.assertCompatible(ty, valueTy, value.line);
} else {
ty = valueTy;
}
}
if (!ty) {
this.error(node.line, `could not infer type of empty array`);
this.fail();
}
const length = node.kind.values.length;
return Ty.create("Array", { ty, length });
}
if (node.is("CallExpr")) {
return this.checkCall(node);
}

View File

@ -240,6 +240,19 @@ export class Parser {
const expr = this.parseExpr();
this.mustEat(")");
return expr;
} else if (this.eat("[")) {
const values: ast.Node[] = [];
if (!this.done && !this.test("]")) {
values.push(this.parseExpr());
while (this.eat(",")) {
if (this.test("]")) {
break;
}
values.push(this.parseExpr());
}
}
this.mustEat("]");
return ast.Node.create(loc, "ArrayExpr", { values });
} else {
this.mustEat("<expression>");
throw new Error();
@ -318,7 +331,7 @@ export type Tok = { type: string; value: string; line: number };
const keywordPattern =
/^(?:fn)|(?:return)|(?:let)|(?:if)|(?:else)|(?:while)|(?:break)|(?:or)|(?:and)|(?:not)|(?:mut)$/;
const operatorPattern =
/((?:\->)|(?:==)|(?:!=)|(?:<=)|(?:>=)|(?:<<)|(?:>>)|[\n\(\)\{\}\,\.\;\:\!\=\<\>\&\^\|\+\-\*\/\%])/g;
/((?:\->)|(?:==)|(?:!=)|(?:<=)|(?:>=)|(?:<<)|(?:>>)|[\n\(\)\{\}\[\]\,\.\;\:\!\=\<\>\&\^\|\+\-\*\/\%])/g;
export function tokenize(text: string): Tok[] {
return text

View File

@ -132,5 +132,6 @@ export type TyKind =
| { tag: "Bool" }
| { tag: "Ptr"; ty: Ty }
| { tag: "PtrMut"; ty: Ty }
| { tag: "Array"; ty: Ty; length: number }
| { tag: "Fn"; params: Ty[]; retTy: Ty }
| { tag: "FnStmt"; ty: Ty; stmt: ast.NodeWithKind<"FnStmt"> };

6
tests/_array.ethlang Normal file
View File

@ -0,0 +1,6 @@
fn main()
{
let array = [1, 2, 3];
}

View File

@ -5,7 +5,7 @@ set -e
TEST_DIR=$(dirname $0)
SRC_DIR=$TEST_DIR/../src
TEST_SRC=$(find $TEST_DIR -name '*.ethlang')
TEST_SRC=$(find $TEST_DIR -name '*.ethlang' -and -not -name "_*")
count_total=0
count_succeeded=0