diff --git a/internal/parser/parser.go b/internal/parser/parser.go
index 30e3d9e..60d7ad7 100644
--- a/internal/parser/parser.go
+++ b/internal/parser/parser.go
@@ -1,14 +1,411 @@
package parser
import (
+ "errors"
+ "slices"
"strings"
"github.com/hazemKrimi/jack-compiler/internal/tokenizer"
)
-func ParseTokens(tokens []tokenizer.Token) string {
+func compileClassVarDec(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || !slices.Contains([]string{"static", "field"}, tokens[*index].Value) {
+ return nil
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
+ return errors.New("Invalid variable type name!")
+ }
+
+ if tokens[*index].Type == tokenizer.KEYWORD {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ } else {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ }
+
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ for tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
+ return errors.New("Missing semicolon!")
+ }
+
+ return compileClassVarDec(output, tokens, index)
+}
+
+func compileParameterList(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
+ return errors.New("Invalid variable type name!")
+ }
+
+ if tokens[*index].Type == tokenizer.KEYWORD {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ } else {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ }
+
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
+ return compileParameterList(output, tokens, index)
+ }
+
+ return nil
+}
+
+func compileVariableDeclaration(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || tokens[*index].Value != "var" {
+ return nil
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"int", "char", "boolean"}, tokens[*index].Value) {
+ return errors.New("Invalid variable type name!")
+ }
+
+ if tokens[*index].Type == tokenizer.KEYWORD {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ } else {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ }
+
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ for tokens[*index].Type == tokenizer.SYMBOL && tokens[*index].Value == "," {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
+ return errors.New("Missing semicolon!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ return compileVariableDeclaration(output, tokens, index)
+}
+
+func compileLetStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || tokens[*index].Value != "let" {
+ return errors.New("Invalid let statement!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "=" {
+ return errors.New("Missing assignment!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ // TODO: Change to expression compilation
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid variable name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
+ return errors.New("Missing semicolon!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ return nil
+}
+
+func compileIfStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ return nil
+}
+
+func compileWhileStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ return nil
+}
+
+func compileDoStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || tokens[*index].Value != "do" {
+ return errors.New("Invalid return statement!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ return nil
+}
+
+func compileReturnStatement(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || tokens[*index].Value != "return" {
+ return errors.New("Invalid return statement!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ // TODO: Change to expression compilation
+ if tokens[*index].Type == tokenizer.IDENTIFIER {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ";" {
+ return errors.New("Missing semicolon!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ (*index)++
+
+ return nil
+}
+
+func compileStatements(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD {
+ return errors.New("Invalid statement!")
+ }
+
+ output.WriteString("<")
+ output.WriteString(tokens[*index].Value)
+ output.WriteString("Statement>\n")
+
+ switch tokens[*index].Value {
+ case "let":
+ if err := compileLetStatement(output, tokens, index); err != nil {
+ return err
+ }
+ case "if":
+ if err := compileIfStatement(output, tokens, index); err != nil {
+ return err
+ }
+ case "while":
+ if err := compileWhileStatement(output, tokens, index); err != nil {
+ return err
+ }
+ case "do":
+ if err := compileDoStatement(output, tokens, index); err != nil {
+ return err
+ }
+ case "return":
+ if err := compileReturnStatement(output, tokens, index); err != nil {
+ return err
+ }
+ }
+
+ output.WriteString("")
+ output.WriteString(tokens[*index].Value)
+ output.WriteString("Statement>\n")
+
+ return compileStatements(output, tokens, index)
+}
+
+func compileSubroutineBody(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type == tokenizer.KEYWORD && tokens[*index].Value == "var" {
+ output.WriteString("\n")
+
+ if err := compileVariableDeclaration(output, tokens, index); err != nil {
+ return err
+ }
+
+ output.WriteString("\n")
+ }
+
+ output.WriteString("\n")
+
+ if err := compileStatements(output, tokens, index); err != nil {
+ return err
+ }
+
+ output.WriteString("\n")
+
+ return nil
+}
+
+func compileSubroutineDeclaration(output *strings.Builder, tokens []tokenizer.Token, index *int) error {
+ if tokens[*index].Type != tokenizer.KEYWORD || !slices.Contains([]string{"constructor", "method", "function"}, tokens[*index].Value) {
+ return nil
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if !slices.Contains([]tokenizer.TokenType{tokenizer.KEYWORD, tokenizer.IDENTIFIER}, tokens[*index].Type) || !slices.Contains([]string{"void", "int", "char", "boolean"}, tokens[*index].Value) {
+ return errors.New("Invalid subroutine return type!")
+ }
+
+ if tokens[*index].Type == tokenizer.KEYWORD {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ } else {
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ }
+
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid subroutine name!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "(" {
+ return errors.New("Missing subroutine opening parenthese!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ output.WriteString("\n")
+
+ if err := compileParameterList(output, tokens, index); err != nil {
+ return err
+ }
+
+ output.WriteString("\n")
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != ")" {
+ return errors.New("Missing subroutine closing parenthese!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ output.WriteString("\n")
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "{" {
+ return errors.New("Missing subroutine opening curly brace!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ if err := compileSubroutineBody(output, tokens, index); err != nil {
+ return err
+ }
+
+ if tokens[*index].Type != tokenizer.SYMBOL || tokens[*index].Value != "}" {
+ return errors.New("Missing subroutine closing curly brace!")
+ }
+
+ output.WriteString(" " + tokens[*index].Value + " \n")
+ *(index)++
+
+ output.WriteString("\n")
+
+ return compileSubroutineDeclaration(output, tokens, index)
+}
+
+func compileClass(output *strings.Builder, tokens []tokenizer.Token) error {
+ index := 0
+
+ output.WriteString("\n")
+
+ if tokens[index].Type != tokenizer.KEYWORD || tokens[index].Value != "class" {
+ return errors.New("Jack file must contain one class!")
+ }
+
+ output.WriteString(" " + tokens[index].Value + " \n")
+ index++
+
+ if tokens[index].Type != tokenizer.IDENTIFIER {
+ return errors.New("Invalid class name!")
+ }
+
+ output.WriteString(" " + tokens[index].Value + " \n")
+ index++
+
+ if tokens[index].Type != tokenizer.SYMBOL || tokens[index].Value != "{" {
+ return errors.New("Missing class opening curly brace!")
+ }
+
+ output.WriteString(" " + tokens[index].Value + " \n")
+ index++
+
+ output.WriteString("\n")
+
+ if err := compileClassVarDec(output, tokens, &index); err != nil {
+ return err
+ }
+
+ output.WriteString("\n")
+ output.WriteString("\n")
+
+ if err := compileSubroutineDeclaration(output, tokens, &index); err != nil {
+ return err
+ }
+
+ output.WriteString("\n")
+
+ if tokens[index].Type != tokenizer.SYMBOL || tokens[index].Value != "}" {
+ return errors.New("Missing class closing curly brace!")
+ }
+
+ output.WriteString(" " + tokens[index].Value + " \n")
+ output.WriteString("\n")
+
+ return nil
+}
+
+func ParseTokens(tokens []tokenizer.Token) (string, error) {
var output strings.Builder
+ if err := compileClass(&output, tokens); err != nil {
+ return "", err
+ }
+
output.WriteString("\n")
for _, token := range tokens {
@@ -41,5 +438,5 @@ func ParseTokens(tokens []tokenizer.Token) string {
output.WriteString("\n")
- return output.String()
+ return output.String(), nil
}