diff --git a/README.md b/README.md
index 5127d47..dbb43e3 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,13 @@
-
-
-
-
-
-
-
Zep Language
- Compiles to WebAssembly.
Tuned for WebAssembly.
-
+
+
+███████╗███████╗██████╗
+╚══███╔╝██╔════╝██╔══██╗
+ ███╔╝ █████╗ ██████╔╝
+ ███╔╝ ██╔══╝ ██╔═══╝
+███████╗███████╗██║
+╚══════╝╚══════╝╚═╝
+
+v0.0.0-wip
## Capabilities
- ✅ Tokenizer
diff --git a/src/ast/nodes/EnumDeclaration.ts b/src/ast/nodes/EnumDeclaration.ts
new file mode 100644
index 0000000..468190f
--- /dev/null
+++ b/src/ast/nodes/EnumDeclaration.ts
@@ -0,0 +1,14 @@
+import { EnumElement } from "./EnumElement.js";
+import { Identifier } from "./Identifier.js";
+import { Statement } from "./Statement.js";
+
+export class EnumDeclaration extends Statement {
+ public nameOf: string = "EnumDeclaration";
+ public name: Identifier;
+ public elements: EnumElement[];
+ constructor(name: Identifier, elements: EnumElement[] = []) {
+ super();
+ this.name = name;
+ this.elements = elements;
+ }
+}
diff --git a/src/ast/nodes/EnumElement.ts b/src/ast/nodes/EnumElement.ts
new file mode 100644
index 0000000..51b11a9
--- /dev/null
+++ b/src/ast/nodes/EnumElement.ts
@@ -0,0 +1,14 @@
+import { Identifier } from "./Identifier.js";
+import { NumberLiteral } from "./NumberLiteral.js";
+import { Statement } from "./Statement.js";
+
+export class EnumElement extends Statement {
+ public nameOf: string = "EnumElement";
+ public name: Identifier;
+ public value: NumberLiteral;
+ constructor(name: Identifier, value: NumberLiteral) {
+ super();
+ this.name = name;
+ this.value = value;
+ }
+}
diff --git a/src/ast/nodes/ReferenceExpression.ts b/src/ast/nodes/ReferenceExpression.ts
index 4eb40b5..ca493bd 100644
--- a/src/ast/nodes/ReferenceExpression.ts
+++ b/src/ast/nodes/ReferenceExpression.ts
@@ -3,7 +3,7 @@ import { Statement } from "./Statement";
export class ReferenceExpression extends Expression {
public nameOf: string = "ReferenceExpression";
- constructor(public referencing: Statement) {
+ constructor(public name: string, public referencing: Statement) {
super();
}
}
diff --git a/src/parser/index.ts b/src/parser/index.ts
index c4ff962..5595142 100644
--- a/src/parser/index.ts
+++ b/src/parser/index.ts
@@ -32,6 +32,8 @@ import { BooleanLiteral } from "../ast/nodes/BooleanLiteral.js";
import { Node } from "../ast/nodes/Node.js";
import { BranchStatement } from "../ast/nodes/BranchStatement.js";
import { BranchToStatement } from "../ast/nodes/BranchToStatement.js";
+import { EnumDeclaration } from "../ast/nodes/EnumDeclaration.js";
+import { EnumElement } from "../ast/nodes/EnumElement.js";
export class Parser {
public program: Program = new Program("test.zp");
@@ -56,6 +58,8 @@ export class Parser {
state.resume();
if ((node = this.parseVariableDeclaration(scope))) return node;
state.resume();
+ if ((node = this.parseEnumDeclaration(scope))) return node;
+ state.resume();
return null;
}
parseStatement(scope: Scope = this.program.globalScope): Statement | null {
@@ -161,6 +165,115 @@ export class Parser {
scope.add(name.text, node);
return node;
}
+ parseFunctionDeclaration(
+ scope: Scope = this.program.globalScope,
+ ): FunctionDeclaration | null {
+ const state = this.tokenizer.createState();
+
+ let exported = false;
+
+ const exp = this.parseModifierExpression();
+ if (!exp) state.resume();
+ else if (exp.tag.data == "export") exported = true;
+ const fn = this.tokenizer.getToken();
+ if (!isIdentifier(fn) || fn.text !== "fn") return null;
+
+ const name = this.tokenizer.getToken();
+ if (!isIdentifier(name)) return null;
+ if (this.tokenizer.getToken().token !== Token.LeftParen) return null;
+ const params: ParameterExpression[] = [];
+ const blockScope = new Scope(scope);
+ while (true) {
+ const param = this.parseParameterExpression(blockScope);
+ if (!param) break;
+ params.push(param);
+ const tok = this.tokenizer.getToken().token;
+ if (tok !== Token.Comma) break;
+ }
+ if (this.tokenizer.getToken().token !== Token.Sub) return null;
+ if (this.tokenizer.getToken().token !== Token.GreaterThan) return null;
+ const returnType = this.tokenizer.getToken();
+ if (!isBuiltinType(returnType)) return null;
+ const block = this.parseBlockExpression(blockScope);
+ if (!block) return null;
+
+ const node = new FunctionDeclaration(
+ new Identifier(name.text, name.range),
+ params,
+ new TypeExpression([returnType.text], false),
+ block,
+ new Scope(scope),
+ exported
+ );
+
+ if (scope.parentScope) {
+ if (exported) {
+ new SyntaxError(
+ this.program,
+ "Warn", "Exported functions must occur at the global scope! Not exporting function and moving on.",
+ 0x1,
+ fn.range,
+ "WARN"
+ );
+ } else {
+ new SyntaxError(
+ this.program,
+ "Error", "Closures not yet supported!",
+ 0x2,
+ fn.range,
+ "FAIL"
+ );
+ }
+ }
+ this.program.globalScope.add(name.text, node);
+ this.program.topLevelStatements.push(node);
+ return node;
+ }
+ parseEnumDeclaration(
+ scope: Scope = this.program.globalScope,
+ ): EnumDeclaration | null {
+ this.tokenizer.createState();
+ if (this.tokenizer.getToken().text != "enum") return null;
+ const name = this.tokenizer.getToken();
+ if (this.tokenizer.getToken().text != "{") return null;
+
+ const elements: EnumElement[] = [];
+
+ let index = 0;
+ while (true) {
+ const name = this.tokenizer.getToken();
+ if (name.token !== Token.Identifier) return null;
+ const trailing = this.tokenizer.getToken();
+ if (trailing.text === "}" || trailing.text === ",") {
+ const element = new EnumElement(
+ new Identifier(
+ name.text,
+ name.range
+ ),
+ new NumberLiteral(
+ index.toString()
+ )
+ );
+
+ index++;
+ elements.push(element);
+ if (trailing.text === "}") break;
+ }
+ }
+
+ const node = new EnumDeclaration(
+ new Identifier(
+ name.text,
+ name.range
+ ),
+ elements
+ );
+
+ this.program.globalScope.add(name.text, node);
+ this.program.topLevelStatements.push(node);
+
+ return node;
+ }
parseIfStatement(
scope: Scope = this.program.globalScope,
): IfStatement | null {
@@ -235,71 +348,6 @@ export class Parser {
);
return node;
}
-
- parseFunctionDeclaration(
- scope: Scope = this.program.globalScope,
- ): FunctionDeclaration | null {
- const state = this.tokenizer.createState();
-
- let exported = false;
-
- const exp = this.parseModifierExpression();
- if (!exp) state.resume();
- else if (exp.tag.data == "export") exported = true;
- const fn = this.tokenizer.getToken();
- if (!isIdentifier(fn) || fn.text !== "fn") return null;
-
- const name = this.tokenizer.getToken();
- if (!isIdentifier(name)) return null;
- if (this.tokenizer.getToken().token !== Token.LeftParen) return null;
- const params: ParameterExpression[] = [];
- const blockScope = new Scope(scope);
- while (true) {
- const param = this.parseParameterExpression(blockScope);
- if (!param) break;
- params.push(param);
- const tok = this.tokenizer.getToken().token;
- if (tok !== Token.Comma) break;
- }
- if (this.tokenizer.getToken().token !== Token.Sub) return null;
- if (this.tokenizer.getToken().token !== Token.GreaterThan) return null;
- const returnType = this.tokenizer.getToken();
- if (!isBuiltinType(returnType)) return null;
- const block = this.parseBlockExpression(blockScope);
- if (!block) return null;
-
- const node = new FunctionDeclaration(
- new Identifier(name.text, name.range),
- params,
- new TypeExpression([returnType.text], false),
- block,
- new Scope(scope),
- exported
- );
-
- if (scope.parentScope) {
- if (exported) {
- new SyntaxError(
- this.program,
- "Warn", "Exported functions must occur at the global scope! Not exporting function and moving on.",
- 0x1,
- fn.range,
- "WARN"
- );
- } else {
- new SyntaxError(
- this.program,
- "Error", "Closures not yet supported!",
- 0x2,
- fn.range,
- "FAIL"
- );
- }
- }
- this.program.globalScope.add(name.text, node);
- this.program.topLevelStatements.push(node);
- return node;
- }
parseFunctionImport(
scope: Scope = this.program.globalScope,
): FunctionImport | null {
@@ -490,7 +538,6 @@ export class Parser {
args,
);
- this.program.statements.push(node);
return node;
}
parseReferenceExpression(
@@ -498,7 +545,7 @@ export class Parser {
): ReferenceExpression | null {
const id = this.tokenizer.getToken();
if (!scope.has(id.text)) return null;
- return new ReferenceExpression(scope.get(id.text)! as Statement);
+ return new ReferenceExpression(id.text, scope.get(id.text)! as Statement);
}
parseReturnStatement(
scope: Scope = this.program.globalScope,
@@ -551,7 +598,7 @@ export class Parser {
}
if (left instanceof Identifier) {
if (scope.has(left.data)) {
- left = new ReferenceExpression(left);
+ left = new ReferenceExpression(left.data, left);
} else {
new TokenMismatchError(
`Cannot find name ${left.data} in scope`,
@@ -562,7 +609,6 @@ export class Parser {
}
}
const node = new BinaryExpression(left, op, right);
- this.program.statements.push(node);
// Check scope
return node;
}
diff --git a/src/test.ts b/src/test.ts
index bea53be..c2cc7bc 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -1,20 +1,18 @@
+import { writeFileSync } from "fs";
import { Parser } from "./parser";
import { Tokenizer } from "./tokenizer";
-import { TreeObject, asTree } from "treeify";
-import { Generator } from "./generator/index.js";
-import { readFileSync, writeFileSync } from "fs";
-import { execSync } from "child_process";
-import { FunctionImport } from "./ast/nodes/FunctionImport.js";
-import { VariableDeclaration } from "./ast/nodes/VariableDeclaration.js";
-import { FunctionDeclaration } from "./ast/nodes/Function.js";
import { Transpile } from "./transpiler/transpiler";
const start = Date.now();
const tokenizer = new Tokenizer(`
+enum Axis {
+ X,
+ Y,
+ Z
+}
+
#[export]: add
fn add(a: i32, b: i32) -> i32 {
- #[export]: main
- fn main() -> none {}
i32? c = a + b
rt c
}
@@ -25,4 +23,8 @@ const parser = new Parser(tokenizer, "test.zp");
const program = parser.parseProgram();
//console.dir(program, { depth: null });
console.log(program);
-console.log("Transpiled:\n" + Transpile.from(program));
+
+const transpiled = Transpile.from(program);
+console.log("Transpiled:\n" + transpiled);
+
+writeFileSync("./test.ts", transpiled);
\ No newline at end of file
diff --git a/src/transpiler/transpiler.ts b/src/transpiler/transpiler.ts
index e967db9..182ffb4 100644
--- a/src/transpiler/transpiler.ts
+++ b/src/transpiler/transpiler.ts
@@ -1,6 +1,7 @@
import { Program } from "../ast/Program";
import { BinaryExpression } from "../ast/nodes/BinaryExpression";
import { BooleanLiteral } from "../ast/nodes/BooleanLiteral";
+import { EnumDeclaration } from "../ast/nodes/EnumDeclaration";
import { FunctionDeclaration } from "../ast/nodes/Function";
import { Identifier } from "../ast/nodes/Identifier";
import { Node } from "../ast/nodes/Node";
@@ -22,27 +23,28 @@ export class Transpile {
}
return out;
}
- if (node instanceof NumberLiteral) return Transpile.num(node);
- if (node instanceof StringLiteral) return Transpile.str(node);
- if (node instanceof VariableDeclaration) return Transpile.var(node);
- if (node instanceof FunctionDeclaration) return Transpile.fn(node);
- if (node instanceof BinaryExpression) return Transpile.binxp(node);
- if (node instanceof ReturnStatement) return Transpile.rt(node);
- if (node instanceof ReferenceExpression) return Transpile.ref(node);
- if (node instanceof ParameterExpression) return Transpile.param(node);
- if (node instanceof Identifier) return Transpile.id(node);
+ if (node instanceof NumberLiteral) return Transpile.NumberLiteral(node);
+ if (node instanceof StringLiteral) return Transpile.StringLiteral(node);
+ if (node instanceof VariableDeclaration) return Transpile.VariableDeclaration(node);
+ if (node instanceof FunctionDeclaration) return Transpile.FunctionDeclaration(node);
+ if (node instanceof EnumDeclaration) return Transpile.EnumDeclaration(node);
+ if (node instanceof BinaryExpression) return Transpile.BinaryExpression(node);
+ if (node instanceof ReturnStatement) return Transpile.ReturnStatement(node);
+ if (node instanceof ReferenceExpression) return Transpile.ReferenceExpression(node);
+ if (node instanceof ParameterExpression) return Transpile.ParameterExpression(node);
+ if (node instanceof Identifier) return Transpile.Identifier(node);
return "nop";
}
- static num(node: NumberLiteral) {
+ static NumberLiteral(node: NumberLiteral) {
return node.data;
}
- static str(node: StringLiteral) {
+ static StringLiteral(node: StringLiteral) {
return node.data;
}
- static var(node: VariableDeclaration) {
- return `${depth}${node.mutable ? "let" : "const"} ${node.name.data} = ${Transpile.from(node.value)};`;
+ static VariableDeclaration(node: VariableDeclaration) {
+ return `${depth}${node.mutable ? "let" : "const"} ${node.name.data} = ${Transpile.from(node.value)}`;
}
- static fn(node: FunctionDeclaration) {
+ static FunctionDeclaration(node: FunctionDeclaration) {
let params = "";
let body = "";
for (const param of node.parameters) {
@@ -59,19 +61,36 @@ export class Transpile {
// Can be done more efficiently with a loop - 1
return `${depth}${node.exported ? "export " : ""}function ${node.name.data}(${params}) {${body ? "\n" + body : ""}}`;
}
- static binxp(node: BinaryExpression) {
+ static EnumDeclaration(node: EnumDeclaration) {
+ let body = "";
+ const end = node.elements.length - 1;
+
+ depth += " ";
+ for (let i = 0; i < end; i++) {
+ const element = node.elements[i];
+ body += `${depth}${element.name.data} = ${element.value.data},\n`;
+ }
+ const lastElement = node.elements[end];
+ body += `${depth}${lastElement.name.data} = ${lastElement.value.data}\n`;
+
+ depth = depth.slice(0, depth.length - 2);
+
+ return `enum ${node.name.data} {\n${body}}`;
+ }
+ static BinaryExpression(node: BinaryExpression) {
return Transpile.from(node.left) + " " + node.operand + " " + Transpile.from(node.right);
}
- static rt(node: ReturnStatement) {
- return depth + Transpile.from(node.returning);
+ static ReturnStatement(node: ReturnStatement) {
+ // @ts-ignore
+ return depth + "return " + node.returning.name;
}
- static ref(node: ReferenceExpression) {
+ static ReferenceExpression(node: ReferenceExpression) {
return Transpile.from(node.referencing);
}
- static id(node: Identifier) {
+ static Identifier(node: Identifier) {
return node.data;
}
- static param(node: ParameterExpression) {
+ static ParameterExpression(node: ParameterExpression) {
return node.name.data;
}
}
\ No newline at end of file
diff --git a/test.ts b/test.ts
new file mode 100644
index 0000000..f6e032c
--- /dev/null
+++ b/test.ts
@@ -0,0 +1,9 @@
+enum Axis {
+ X = 0,
+ Y = 1,
+ Z = 2
+}
+export function add(a: i32, b: i32) {
+ let c = a + b
+ return c
+}